//============================================================================================
/**
 * @file	pkthln_opening.c
 * @brief	開会式&閉会式
 * @author	Nozomu Saito -> Genya Hosaka(引継ぎ)
 * @note	下画面：ポケスロン用アクター 上画面：CATS
 */
//============================================================================================

#include "common.h"
#include "gflib/touchpanel.h"
#include "system/wipe.h"
#include "system/wordset.h"
#include "system/render_oam.h"
#include "system/arc_util.h"
#include "system/pm_overlay.h"
#include "system/pmfprint.h"
#include "system/window.h"
#include "system/snd_tool.h"
#include "system/snd_perap.h"
#include "system/fontproc.h"
#include "system/gra_tool.h"			///< ポケグラ読み込み
#include "gflib/heapsys.h"				///< ヒープチェックに使用
#include "gflib/strbuf_family.h"
#include "msgdata/msg.naix"
#include "msgdata/msg_pokethlon.h"

#include "savedata/pkthln_svdata.h"

#include "../event_se_def.h"
#include "../evt_msg.h"
#include "../evt_cats.h"
#include "../evt_npcobj.h"

#include "../../pokethlon_common.h"
#include "../../pkthln_obj_common.h"
#include "../../poke_clact.h"
#include "../../poke_clact_move.h"
#include "../../pkthln_poke_act.h"
#include "../../pkthln_comm_pack.h"
#include "../../cmn_res.h"

#include "../../../pokethlon_museum/museum_util.h"

#include "../pkthev_oped.naix"

#include "pkthln_opening.h"

FS_EXTERN_OVERLAY( pkthln_common );

#ifdef _NITRO
		// 構造体が想定のサイズとなっているかチェック
		SDK_COMPILER_ASSERT(sizeof(OPENING_COMM_WORK) == 36);
		SDK_COMPILER_ASSERT(sizeof(OPED_COMM_CHILD_WORK) == 36);
		SDK_COMPILER_ASSERT(sizeof(ENDING_COMM_WORK) == 36);
#endif

#ifdef PM_DEBUG
		extern DEBUG_PKTHLN_WORK DebugPkthlnWk;
#endif

//--------------------------------------------------------------
///	ReciveShareData取得マクロ
// ※変数を定義するので、行頭で使用すること
// ※バッティングを避けるために引数で変数名を指定している。
//==============================================================
// -- opening --
#define GET_OP_RECIVE(work, data, parent) COMM_EVENT_COMMON_DATA* data;\
	OPENING_COMM_PTR parent; \
	data = PTFrame_GetEvtComCmnData( work ); \
	parent = PKTHLN_CommPack_GetData( &data->ReciveShareData ); \
	GF_ASSERT(work); GF_ASSERT(data); GF_ASSERT(parent);

// -- ending --
#define GET_ED_RECIVE(work, data, parent) COMM_EVENT_COMMON_DATA* data;\
	ENDING_COMM_PTR parent; \
	data = PTFrame_GetEvtComCmnData( work ); \
	parent = PKTHLN_CommPack_GetData( &data->ReciveShareData ); \
	GF_ASSERT(work); GF_ASSERT(data); GF_ASSERT(parent);

//=============================================================================
/**
 *								定数定義
 */
//=============================================================================
#define OPED_HEAP_SIZE	(0x60000)
#define PCLACT_TCB_PRIORITY	(1)

enum
{
	TEAM_NUM = ENTRY_MEMBER_NUM_MAX,		///< チーム数
	ALL_POKE_NUM = ENTRY_MAX * TEAM_NUM,	///< 画面上にいる全てのポケモン数
	CATS_DISTANCE = FX32_CONST(524),		///< 2画面の距離
	MEDAL_NUM = 2,							///< メダルの最大数
	ANM_WAIT = 60,							///< ポケモンアニメのウェイト
	FUN_LEVEL_NUM = 13,
	EVT_SCORE_ADD_WAIT = 30,

	// -- 通信用データ --
	BLAST_DAT_MAX = 29,
	BLAST_MSG_HEADER = msg_pkthln_op01_1,
	BLAST_MSG_PATTERN = 4,

	// -- 紙ふぶき --
	// １つあたり最大 6 oam
	// 6 * 15 = 90 oam
	PTC_NUM = 15,				///< 紙ふぶきワークの数
	PTC_PAL_OFS = 11,			///< パレットの参照位置
	PTC_ANM_ID_0 = 11,
	PTC_ANM_ID_1 = 12,
	PTC_ADD_FRAME_BASE = 4,		///< 最低限のウェイトフレーム
	PTC_ADD_FRAME_RND = 8,		///< 加算する乱数の上限
	PTC_ADD_DEF = 2,			///< 1回で増える数規定値
	PTC_ADD_RND_MAX = 2,		///< 一回に増える数の乱数幅( PTC_ADD_DEF + 1~この値まで)

	BD_SCORE_MAX = 999,	///< スコアボードのスコアの最大値

	// -- MASK --
	MASK_ALL =  GX_PLANEMASK_OBJ | GX_PLANEMASK_BG0 | GX_PLANEMASK_BG1 | GX_PLANEMASK_BG2 | GX_PLANEMASK_BG3,
};

// -- ポケモンの整列基準座標
#define ARRAY_BASE_Y	(64)
#define ARRAY_BASE_X	(48)

// -- ポケモンの初期位置
#define DRAW_OFS_X (16)
#define DRAW_OFS_Y (16)
//#define DRAW_OFS_X_S	(16)
//#define DRAW_OFS_Y_S	(16)
//#define DRAW_OFS_X_L	(32)
//#define DRAW_OFS_Y_L	(32)

#define POKE_PRIORITY	(3)

#define OPENING_ACT_NUM	( OPENING_EVENT_POKE_NUM*3 )	//ポケモン影マーカー12

//--------------------------------------------------------------
///	CATS OBJ用 : OBJ ID
//==============================================================
enum
{
	//-- MAX --
	OPENING_EVENT_POKE_NUM = 12,
	BOARD_SCORE_NUM  = 3,								///< スコアに使うOBJ数
	BOARD_CAP_NUM = 1 + BOARD_SCORE_NUM,				///< ボードに使うOBJ数
	BOARD_NUM = 4,										///< 表示するボード数

	CAP_ID_MMO_MAX = 4+1,								///< 参加者＋司会者の数
	CAP_ID_BOARD_MAX = BOARD_NUM * BOARD_CAP_NUM,		///< 全てのボードで使うCAP数

	//-- CAP_ID --
	///< MMO:必ず0-5にすること!!
	CAP_ID_BOARD_HEAD = CAP_ID_MMO_MAX,
	CAP_ID_POKEGRA_HEAD = CAP_ID_BOARD_HEAD + CAP_ID_BOARD_MAX,
	CAP_ID_MDL_HEAD = CAP_ID_POKEGRA_HEAD + ENTRY_MAX,
	CAP_ID_MAX = CAP_ID_MDL_HEAD + MEDAL_NUM,

	CAP_ID_MMO_TALKER = 4,			///< 司会者のIDX

	// -- OBJ_ID --
//	OBJ_NUM_MAX = OPENING_EVENT_POKE_NUM + 1 + 1,				///< ポケモン12+影+マーカー
//	OBJ_ID_S_MMO_HEAD,											///< 参加者
//	OBJ_ID_S_BOARD_HEAD = OBJ_ID_S_MMO_HEAD + CAP_ID_MMO_MAX,	///< スコアボード
//	OBJ_ID_S_BOARD_HEAD + CAP_ID_BOARD_MAX,
	OBJ_ID_MAX =  128, // とりあえずmax
};

//--------------------------------------------------------------
///	メインシーケンス
//==============================================================
enum {
	OP_SEQ_START,
	OP_SEQ_FADE_OUT,
	OP_SEQ_FADE_OUT_WAIT,
	OP_SEQ_FADE_IN,
	OP_SEQ_FADE_WAIT,
	OP_SEQ_TEAM_INST_PRE,
	OP_SEQ_TEAM_INST,
	OP_SEQ_INST_ANM_WAIT,
	OP_SEQ_END,
};

//--------------------------------------------------------------
///	CATS OBJ用：リソースID
//==============================================================
enum{ CATS_RES_HEAD = 100, }; //OPENING_EVENT_POKE_NUM + 1, }; ///< スロン：ポケアクターで使用するリソース数

enum {
	CHR_ID_S_MMO_HEAD = CATS_RES_HEAD,
	CHR_ID_S_OPED = CHR_ID_S_MMO_HEAD + CAP_ID_MMO_MAX,
	CHR_ID_M_OPED,
	CHR_ID_M_MDL_0,
	CHR_ID_M_MDL_1,
	CHR_ID_M_POKEGRA_0,
	CHR_ID_M_POKEGRA_1,
	CHR_ID_M_POKEGRA_2,
	CHR_ID_MAX,
};

enum {
	PAL_ID_S_MMO_HEAD = CATS_RES_HEAD,
	PAL_ID_S_OPED = PAL_ID_S_MMO_HEAD + CAP_ID_MMO_MAX,
	PAL_ID_M_OPED,
	PAL_ID_M_MDL_0,
	PAL_ID_M_MDL_1,
//	PAL_ID_M_POKEGRA_0,
//	PAL_ID_M_POKEGRA_1,
//	PAL_ID_M_POKEGRA_2,
	PAL_ID_DMY,
	PAL_ID_MAX,
};

enum {
	CEL_ID_MMO = CATS_RES_HEAD,
	CEL_ID_S_OPED,
	CEL_ID_M_OPED,
	CEL_ID_M_MDL,
	CEL_ID_POKEGRA,
	CEL_ID_MAX,
};

enum {
	ANM_ID_MMO = CATS_RES_HEAD,
	ANM_ID_S_OPED,
	ANM_ID_M_OPED,
	ANM_ID_M_MDL,
	ANM_ID_POKEGRA,
	ANM_ID_MAX,
};

//=============================================================================
/**
 *								構造体定義
 */
//=============================================================================
enum
{
	BDCAP_ID_BASE,
	BDCAP_ID_NUM_0,
	BDCAP_ID_NUM_1,
	BDCAP_ID_NUM_2,
};

//--------------------------------------------------------------
///	スコアボード 構造体
//==============================================================
typedef struct {
	CATS_ACT_PTR	Cap[ BOARD_CAP_NUM ];
	u32				Score;		///< 実際のスコア
	u32				ScoreView;	///< 表示スコア
	BOOL			bMove;		///< 移動フラグ
} BOARD_WORK;

//--------------------------------------------------------------
///	スコアボード管理 構造体
//==============================================================
typedef struct {
	BOARD_WORK wkBoard[ BOARD_NUM ];
} BOARD_CNT_WORK;

//--------------------------------------------------------------
///	紙ふぶき 構造体
//==============================================================
typedef struct {
	CATS_ACT_PTR	cap;
	fx32			speed_x_fx;
	fx32			speed_y_fx;
	fx32			pos_x_fx;
	fx32			pos_y_fx;
	u32				cnt : 16;
	u32				turn_lim : 4;
	u32				enable : 1;
	u32				disp_drop : 1;	///< TRUE:下画面
	u32				dammy : 10;
} PTC_EFFECT_WORK;

//--------------------------------------------------------------
///	紙ふぶき管理 構造体
//==============================================================
typedef struct {
	HEAPID HeapID;
	PTC_EFFECT_WORK	ptc[ PTC_NUM ];
	CATS_SYS_PTR csp;
	CATS_RES_PTR crp;
	u32 cnt;
	u32 wait_frame;
	BOOL b_auto;
} PTC_EFFECT_CNT_WORK;


//--------------------------------------------------------------
///	アニメワーク
//==============================================================
typedef struct ANIME_TASK_WORK_tag
{
	u16 Seq;
	int Timer;

	POKE_ACT_PTR PokeActPtr;
	BOOL *AnimeFlg;
}ANIME_TASK_WORK;

//--------------------------------------------------------------
///	順位データ
//==============================================================
typedef struct {
	u32 Score : 16;
	u32 Grade : 8;
	u32 NetID : 4;
	u32 DrawWinPoint : 4;
} GRADE_DATA;

//--------------------------------------------------------------
///	メインワーク
//==============================================================
typedef struct OPENING_WORK_tag
{
	HEAPID			HeapID;
	GF_BGL_INI		*bgl;
	TCB_PTR			Tcb;
	MSG_CNT_PTR		MsgCnt;

	CMN_RES_CNT_PTR	CmnResCntPtr;
	POKE_ACT_CNT_PTR PokeActCntPtr;

	// -- cats --
	CATS_SYS_PTR csp;
	CATS_RES_PTR crp;
	CATS_ACT_PTR cap[ CAP_ID_MAX ];

	ANIME_TASK_WORK *TaskWork;
	BOARD_CNT_WORK* wkBoardCnt;
	PTC_EFFECT_CNT_WORK* wkPtcCnt;

	int NextAnmWait;	///< 次の方向変更までのウェイト
	BOOL AnimeFlg;
	GRADE_DATA Grade[ TEAM_NUM ];	///< 順位データ
	u8	BonusCount[ TEAM_NUM ];	///< 加点された回数

	u8	TeamAnmReq;		///< アニメリクエスト フラグ
	u8	CrsID;			///< コースID
	u8	TeamCnt;		///< チーム用カウンタ
	u8	PokeCnt;		///< ポケモン用カウンタ

	u8	Cnt;			///< 汎用カウンタ
	u8	Seq;			///< シーケンス
	u8	bDraw;			///< 引き分けフラグ
	u8	MsgSeq;			///< メッセージシーケンサ

	BOOL EndFlag;		///< ゲーム終了フラグ
}OPENING_WORK;

//=============================================================================
/**
 *							プロトタイプ宣言
 */
//=============================================================================
// -- prototype --
static void SetVramBank(void);
static void AnimeTask(TCB_PTR tcb, void* work);
static void SetAnimeTask(OPENING_PTR ptr, const u8 inIndex);
static BOOL CheckAnimeTask(OPENING_PTR ptr);
static void SetPokeRectHitTable(RECT_HIT_TBL *rect, int x, int y, int sizx, int sizy);
static void BgInit(GF_BGL_INI * ini);
static void SetGraphic(GF_BGL_INI * ini, const int inHeapID);
static void LoadWinBg(GF_BGL_INI* ini, const int inHeapID);
// -- CATS Util --
static void CATS_Create( OPENING_PTR ptr );
static void CATS_Delete( OPENING_PTR ptr );
static void CATS_AddMapModel( OPENING_PTR ptr );
static void CATS_AddScoreBoard( OPENING_PTR ptr );
static void CATS_AddPokegra( OPENING_PTR ptr );
static void CATS_AddMedal( OPENING_PTR ptr );
static void CATS_TransPokegra( PKTHLN_PTR work, u8 TeamIdx );
static void CATS_LoadRes( PKTHLN_PTR work );
static void CATS_LoadResPokegra(OPENING_PTR ptr);
static void CATS_CreatePokegra( PKTHLN_PTR work, u8 WinTeamID );
static void MANOBJ_Setup(PKTHLN_PTR work);
static void MANOBJ_TransAnimeSeq( CATS_ACT_PTR* ppCap, PKTHLN_PTR work, int NetID, int poke_dir, HEAPID HeapID );
// -- BoardCnt --
static BOARD_CNT_WORK* BoardCnt_Create( HEAPID HeapID, CATS_ACT_PTR* ppCap );
static void BoardCnt_Delete( BOARD_CNT_WORK* wk );
static void BoardCnt_Main( BOARD_CNT_WORK* wk );
static BOOL BoardCnt_CheckEnd( BOARD_CNT_WORK* wk );
static void BoardCnt_StartAdd( BOARD_CNT_WORK* wk, u8 idx, u16 add );
static u32 BoardCnt_GetScore( BOARD_CNT_WORK* wk, u8 idx );
static void BoardCnt_CalcGrade(BOARD_CNT_WORK* wk, GRADE_DATA* pGradeData, u8* pDrawWinPoint );
// -- Board --
static void Board_Main( BOARD_WORK* wk );
static BOOL Board_CheckEnd( BOARD_WORK* wk );
static void Board_StartAdd( BOARD_WORK* wk, u16 add );
// -- PtcEffenct --
static void PtcEffect_Init( PTC_EFFECT_WORK* wk, CATS_SYS_PTR csp, CATS_RES_PTR crp );
static BOOL PtcEffect_Main( PTC_EFFECT_WORK* wk );
static void PtcEffect_DispDrop( PTC_EFFECT_WORK* wk, CATS_SYS_PTR csp, CATS_RES_PTR crp );
// -- PtcEffenctCnt --
static PTC_EFFECT_CNT_WORK* PtcEffectCnt_Create( HEAPID HeapID, CATS_SYS_PTR csp, CATS_RES_PTR crp );
static void PtcEffectCnt_Delete( PTC_EFFECT_CNT_WORK* wk );
static void PtcEffectCnt_Main( PTC_EFFECT_CNT_WORK* wk );
static void PtcEffectCnt_SetAutoAdd( PTC_EFFECT_CNT_WORK* wk, BOOL b_auto );
static void PtcEffectCnt_Add( PTC_EFFECT_CNT_WORK* wk, u8 num );
// -- Common --
static PTH_RC Common_InitFunc(PKTHLN_PTR work, void *pParam);
static BOOL Common_DrawFunc(PKTHLN_PTR work, void *pParam);
static BOOL Common_EndFunc(PKTHLN_PTR work, void *pParam);

static void PrintPokemonName(PKTHLN_PTR work, u8 TeamIdx, u8 pokeIdx, u32 regIdx);
static void PrintTeamScore(PKTHLN_PTR work, u8 TeamIdx, int num);
static void PrintTeamPokemon(PKTHLN_PTR work, u8 TeamIdx, u8 pokeIdx );
static BOOL CheckNoMissPokemonExist(PKTHLN_PTR work);
static BOOL CheckNoMissPokemon(PKTHLN_PTR work, u8 TeamIdx, u8 PokeIdx);
static BOOL CheckPointKingPoke(PKTHLN_PTR work, u8 TeamIdx, u8 PokeIdx);
static BOOL CheckEffortPrizePoke(PKTHLN_PTR work, u8 TeamIdx, u8 PokeIdx );
static u32 GetPtcAddWaitFrame(void);
static u8 GetPokemonBonus(PKTHLN_PTR work, u8 idx );
static int GetEventScore(PKTHLN_PTR work, u8 TeamIdx, u8 EvtCodeIdx );
static u32 GetNoMissScore(OPENING_PTR ptr);
static u32 GetKingPoint(OPENING_PTR);
static u32 GetEffortPoint(OPENING_PTR ptr);
static u8 GetNomissCount(PKTHLN_PTR work);
static u8 GetKingPointCount(PKTHLN_PTR work);
static u8 GetEffortPrizeCount(PKTHLN_PTR work);
static void GetDrawWinPoint(PKTHLN_PTR work, u8 outArray[] );
static u8 GetMedalIdx( u8 crs_idx, u8 mdl_idx );
static u8 GetEffortType( PKTHLN_PTR work );
static u32 GetEffortData( PKTHLN_PTR work, u8 EffortType, u8 TeamIdx, u8 PokeIdx );
static BOOL SearchAddBonus( PKTHLN_PTR work, BOOL (*func)(PKTHLN_PTR,u8,u8), u32 score );
static u32 OP_GetBlastMsgIdx( PKTHLN_PTR work, u8 team_idx );
static u32 OP_GetBlastPoint( PKTHLN_PTR work, u8 team_idx );
static u32 OP_GetFunLevel( PKTHLN_PTR work, u8 team_idx );
static void OP_SendShareData( PKTHLN_PTR work );
static u32 ED_CalcPokeBonus( PKTHLN_PTR work, u8 netID );
static int ED_CalcEffort( PKTHLN_PTR work );
static void ED_SendShareData( PKTHLN_PTR work );
static void ED_SetSvSetData( PKTHLN_PTR work, BOARD_CNT_WORK* wk );
static void WORDSET_RegNum( WORDSET* WordSet, int num, int figre, int bufID );
static int GetFunLevel( int FunNum );
static u32 GetBlastMessageIndexHeader( u32 dat_idx );
static void SetTeamDataRank( u32* outData ,const PKTH_RNK_DATA* p_rnk );
static void SetTeamDataPoint( u8* outPoint, const u32* srcData );
static u32 SelectTeamDataIdxFromPoint( const u8* srcPoint, u8* outPattern );
static void SetCommTeamDataAlone( OP_COMM_TEAM_DATA* outData, PKTHLN_PTR work );
static void SetCommTeamDataComm( OP_COMM_TEAM_DATA* outData, PKTHLN_PTR work, u8 team_idx );
static void SetCommTeamDataNpc( OP_COMM_TEAM_DATA* outData, PKTHLN_PTR work, u8 team_idx );
static int Grade_GetGrade( GRADE_DATA* pData, u8 NetID );
static void Grade_SortDraw( GRADE_DATA* pData );

static BOOL OP_CommMain( PKTHLN_PTR work );
static BOOL ED_CommMain( PKTHLN_PTR work );
static BOOL OP_CheckEndFlag( PKTHLN_PTR work );
static BOOL ED_CheckEndFlag( PKTHLN_PTR work );

static BOOL OPENING_Func_Init(PKTHLN_PTR work, u8 *seq);
static BOOL OPENING_Func_Main(PKTHLN_PTR work, u8 *seq);
static BOOL OPENING_Func_End(PKTHLN_PTR work, u8 *seq);
PKTHLN_FUNC OpeningFuncTbl[] = {
	OPENING_Func_Init,
	OPENING_Func_Main,
	OPENING_Func_End,
};
static BOOL ENDING_Func_Init(PKTHLN_PTR work, u8 *seq);
static BOOL ENDING_Func_Main(PKTHLN_PTR work, u8 *seq);
static BOOL ENDING_Func_End(PKTHLN_PTR work, u8 *seq);
PKTHLN_FUNC EndingFuncTbl[] =
{
	ENDING_Func_Init,
	ENDING_Func_Main,
	ENDING_Func_End,
};

enum {
	OPENING_SEQ_INIT = 0,
	OPENING_SEQ_MAIN,
	OPENING_SEQ_END,
	ENDING_SEQ_INIT = 0,
	ENDING_SEQ_MAIN,
	ENDING_SEQ_END,
};

//=============================================================================
/**
 *								外部公開関数
 */
//=============================================================================
//--------------------------------------------------------------------------------------------
/**
 * 初期化関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
PTH_RC PE_OPENING_InitFunc(PKTHLN_PTR work, void *pParam)
{
	return Common_InitFunc(work, pParam);
}


//--------------------------------------------------------------------------------------------
/**
 * 描画関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_OPENING_DrawFunc(PKTHLN_PTR work, void *pParam)
{
	return Common_DrawFunc(work, pParam);
}

//--------------------------------------------------------------------------------------------
/**
 * 終了関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_OPENING_EndFunc(PKTHLN_PTR work, void *pParam)
{
	return Common_EndFunc(work, pParam);
}

//--------------------------------------------------------------------------------------------
/**
 * 初期化関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
PTH_RC PE_ENDING_InitFunc(PKTHLN_PTR work, void *pParam)
{
	return Common_InitFunc(work, pParam);
}

//--------------------------------------------------------------------------------------------
/**
 * 描画関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_ENDING_DrawFunc(PKTHLN_PTR work, void *pParam)
{
	return Common_DrawFunc(work, pParam);
}

//--------------------------------------------------------------------------------------------
/**
 * 終了関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_ENDING_EndFunc(PKTHLN_PTR work, void *pParam)
{
	return Common_EndFunc(work, pParam);
}



//=============================================================================
/**
 *								static関数
 */
//=============================================================================

//--------------------------------------------------------------------------------------------
/**
 * VRAM設定		ポケスロンでは、ポケモン表示だけで0x30000必要となる。
 * VRAM_AB(0x40000)でないとはいらん
 *
 * @param	none
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetVramBank(void)
{
	GF_BGL_DISPVRAM tbl = {
		GX_VRAM_BG_64_E,				// メイン2DエンジンのBG
		GX_VRAM_BGEXTPLTT_NONE,			// メイン2DエンジンのBG拡張パレット

		GX_VRAM_SUB_BG_128_C,			// サブ2DエンジンのBG
		GX_VRAM_SUB_BGEXTPLTT_NONE,		// サブ2DエンジンのBG拡張パレット

		GX_VRAM_OBJ_256_AB,				// メイン2DエンジンのOBJ
		GX_VRAM_OBJEXTPLTT_NONE,		// メイン2DエンジンのOBJ拡張パレット

		GX_VRAM_SUB_OBJ_16_I,			// サブ2DエンジンのOBJ
		GX_VRAM_SUB_OBJEXTPLTT_NONE,	// サブ2DエンジンのOBJ拡張パレット

		GX_VRAM_TEX_NONE,				// テクスチャイメージスロット
		GX_VRAM_TEXPLTT_NONE			// テクスチャパレットスロット
	};
	GF_Disp_SetBank( &tbl );
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	FALSE
 */
//-----------------------------------------------------------------------------
static BOOL OPENING_Func_Init(PKTHLN_PTR work, u8 *seq)
{
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);

	switch( *seq )
	{
	case 0 :
		// 親なら通信データを設定
		if( PTFrameGetCurrentID(work) == COMM_PARENT_ID )
		{
			OP_SendShareData( work );
		}

		//上画面フェードイン
		WIPE_SYS_Start(	WIPE_PATTERN_S, WIPE_TYPE_SHUTTERIN_DOWN,
				WIPE_TYPE_SHUTTERIN_DOWN, WIPE_FADE_BLACK,
				WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );

		(*seq)++;
		break;

	case 1 :
		if( WIPE_SYS_EndCheck() )
		{
			OS_Printf("開会式画面出ましたよ\n");
			//シーケンスシフト
			PTFrame_SetNextFuncTblIdx(work, OPENING_SEQ_MAIN);
		}
		break;

	default : GF_ASSERT(0);
	}

	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	FALSE
 */
//-----------------------------------------------------------------------------
static BOOL OPENING_Func_Main(PKTHLN_PTR work, u8 *seq)
{
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);
	BOOL bCommWait = FALSE;

	// 通信同期処理
	if( PTFrame_GetGameType(work) == PKTHLN_GAME_COMM )
	{
		bCommWait = OP_CommMain( work );
	}

	//メッセージ駆動
	MSG_CNT_Main( ptr->MsgCnt );

	if( MSG_CNT_IsPrinting( ptr->MsgCnt ) == FALSE && bCommWait == FALSE )
	{
		WORDSET* WordSet = MSG_CNT_GetWordSet( ptr->MsgCnt );
		int code = MSG_ID_NONE;

		//シーケンス処理
		switch(ptr->Seq){
		case OP_SEQ_START:		//開会式の言葉
			//開会式の言葉リクエスト
			code = msg_pkthln_op_start;
			WORDSET_RegisterPkthlnCourse( WordSet, 0, ptr->CrsID );
			ptr->Seq = OP_SEQ_FADE_OUT;
			break;
		case OP_SEQ_FADE_OUT:
			// 画面を一瞬で白に
			WIPE_SetBrightnessFadeOut( WIPE_FADE_WHITE );
			Snd_SePlay( SE_OPED_VOICE1 );
			// 開会SE
			ptr->Seq = OP_SEQ_FADE_OUT_WAIT;
			break;
		case OP_SEQ_FADE_OUT_WAIT:
			if( ptr->Cnt < 4 ){ ptr->Cnt++; }else
			{
				ptr->Cnt = 0;
				ptr->Seq = OP_SEQ_FADE_IN;
			}
			break;
		case OP_SEQ_FADE_IN:
			//下画面フェードインリクエスト
			WIPE_SYS_Start(	WIPE_PATTERN_WMS, WIPE_TYPE_FADEIN,
					WIPE_TYPE_FADEIN, WIPE_FADE_WHITE,
					WIPE_DEF_DIV*4, WIPE_DEF_SYNC, ptr->HeapID );
			ptr->Seq = OP_SEQ_FADE_WAIT;
			break;
		case OP_SEQ_FADE_WAIT:
			//下画面フェード待ち
			if(WIPE_SYS_EndCheck())
			{
				ptr->Seq = OP_SEQ_TEAM_INST_PRE;
			}
			break;
		case OP_SEQ_TEAM_INST_PRE:
			// 選手紹介メッセージ あおり
			{
				COMMON_PLAYER_DATA* cmn_data = PTFrame_GetCmnPlayerDataPtrByID(work, ptr->TeamCnt);

				// NPC
				if( cmn_data->PersonCode > 0 )
				{
					int msg_code = OP_GetBlastMsgIdx( work, ptr->TeamCnt );
					MSG_CNT_PrintNpcMessage( ptr->MsgCnt, msg_code );
				}
				// 主人公
				else
				{
					u32 blast_point;

					code = OP_GetBlastMsgIdx( work, ptr->TeamCnt );
					blast_point = OP_GetBlastPoint( work, ptr->TeamCnt );

					WORDSET_RegNum( WordSet, blast_point, 7, 1 );
				}
			}
			ptr->Seq = OP_SEQ_TEAM_INST;
			break;
		case OP_SEQ_TEAM_INST:
			// トレーナー名レジスト
			WORDSET_RegisterPlayerName( WordSet, 0, PTFrame_GetMyStatus(work, ptr->TeamCnt) );

			// ポケモン名３匹レジスト
			{
				int i;
				for( i=0; i<ENTRY_MAX; i++ )
				{
					PrintPokemonName( work, ptr->TeamCnt, i, i+1 );
				}
			}

			// トレーナー正面を向く
			MANOBJ_TransAnimeSeq( ptr->cap, work, ptr->TeamCnt, POKE_DIR_DOWN, ptr->HeapID );
			CATS_ObjectAnimeSeqSetCap( ptr->cap[ ptr->TeamCnt ], 1 );	// ジャンプ！

			// 紹介効果音
			{
				// pitch調整用テーブル
				static const se_pitch_tbl[ FUN_LEVEL_NUM ] =
				{
					-2 * 32, //0
					-1 * 32,//11
					0 * 32,//26
					1 * 32,//51
					2 * 32,//101
					3 * 32,
					-2 * 16,//501
					-1 * 16,
					0 * 16,
					1 * 16,
					2 * 16,
					3 * 16,
					4 * 16,
				};

				u8 FunLevel;
				u32 label;

				FunLevel = OP_GetFunLevel( work, ptr->TeamCnt );

				if( FunLevel < 5 )
				{
					label = SE_OPED_VOICE1;
				}
				else
				{
					label = SE_OPED_VOICE3;
				}

				Snd_SePitchPlay( label, se_pitch_tbl[ FunLevel ] );
			}

			//チーム紹介メッセージリクエスト
			code = msg_pkthln_op_team;
			//チームアニメーションリクエスト（とりあえず紹介メッセージと同じタイミングで）
			ptr->TeamAnmReq = 1;

			ptr->Seq = OP_SEQ_INST_ANM_WAIT;
			break;
		case OP_SEQ_INST_ANM_WAIT:
			if ( !ptr->TeamAnmReq ){	//アニメ待ち
				if (ptr->TeamCnt >= TEAM_NUM){
					//紹介終了なら、締めの言葉をリクエストして次のシーケンスへ
					code = msg_pkthln_op_end;

					// 子機の終了フラグを立てる
					ptr->EndFlag = TRUE;

					ptr->Seq = OP_SEQ_END;
				}else{
					//次のチーム紹介なら、シーケンスを戻す
					ptr->Seq = OP_SEQ_TEAM_INST_PRE;
				}
			}
			break;
		case OP_SEQ_END:
			// 通信時は親機のEndFlagが立つのを待つ
			if( PTFrame_GetGameType(work) == PKTHLN_GAME_ALONE || OP_CheckEndFlag(work) )
			{
				//アニメタスクを終了させる
				if (CheckAnimeTask(ptr)){
					sys_FreeMemoryEz(ptr->TaskWork);
					TCB_Delete(ptr->Tcb);
				}
				MSG_CNT_PrintEnd( ptr->MsgCnt );

				//シーケンスシフト
				PTFrame_SetNextFuncTblIdx(work, OPENING_SEQ_END);
				return FALSE;
			}
			break;

		default : GF_ASSERT(0);
		}

		//メッセージ作成
		if( code != MSG_ID_NONE )
		{
			MSG_CNT_PrintMessage( ptr->MsgCnt, code );
			// メッセージシーケンスを進める
			ptr->MsgSeq++;
		}
	}

	//アニメコントロール
	if (ptr->TeamAnmReq)
	{
		u8 act_no_base;
		int i;
		act_no_base = ptr->TeamCnt * ENTRY_MAX;

		// -- 初期化
		if (ptr->NextAnmWait++ == 0 )
		{
			for(i=0; i<ENTRY_MAX; i++ )
			{
				POKE_ACT_PTR poke_act = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, act_no_base + i);
				PokeAct_SetDir(poke_act, POKE_DIR_DOWN);
				PokeAct_SetAnm(poke_act, ANM_TYPE_THROW);
			}
		}
		else if (ptr->NextAnmWait++ >= ANM_WAIT)
		{
			//向き戻す
			for(i=0; i<ENTRY_MAX; i++ )
			{
				POKE_ACT_PTR poke_act = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, act_no_base + i);
				PokeAct_SetDir(poke_act, POKE_DIR_UP);
				PokeAct_SetAnm(poke_act, ANM_TYPE_WALK);

				// アニメ再生タイミングをずらす
				{
					PCLACT_PTR pclact_ptr;
					CLACT_WORK_PTR cl_act;
					NNSG2dAnimController* anim_ctrl;

					pclact_ptr = PokeAct_GetPclActPtr( poke_act );
					cl_act = PCLACT_GetClActWorkPtr( pclact_ptr );
					anim_ctrl = CLACT_GetAnimController( cl_act );

					NNS_G2dSetAnimCtrlCurrentTime( anim_ctrl, i*3*FX32_ONE );
				}
			}

			// トレーナー背面に
			MANOBJ_TransAnimeSeq( ptr->cap, work, ptr->TeamCnt, POKE_DIR_UP, ptr->HeapID );

			//1チームのアニメ終了
			ptr->TeamAnmReq = 0;
			//次のプレーヤー
			ptr->TeamCnt++;

			ptr->NextAnmWait = 0;
		}
	}

#ifdef PM_DEBUG
	if (sys.trg & PAD_BUTTON_X){
		// ワイプ状態を念のため解除
		WIPE_SYS_ExeEnd();

		//アニメタスクを終了させる
		if (CheckAnimeTask(ptr)){
			sys_FreeMemoryEz(ptr->TaskWork);
			TCB_Delete(ptr->Tcb);
		}

		MSG_CNT_PrintEnd( ptr->MsgCnt );

		//シーケンスシフト
		PTFrame_SetNextFuncTblIdx(work, OPENING_SEQ_END);
	}
#endif

	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	TRUE
 */
//-----------------------------------------------------------------------------
static BOOL OPENING_Func_End(PKTHLN_PTR work, u8 *seq)
{
	enum{ WIPE_FRAME = 90, };

	// ホワイトアウト
	switch( *seq )
	{
	case 0:

#ifdef PM_DEBUG
		if (sys.cont & PAD_BUTTON_X){ return TRUE; }
#endif
		{
			HEAPID heap_id = PTFrame_GetHeapID( work );

			WIPE_SYS_Start(	WIPE_PATTERN_WMS, WIPE_TYPE_FADEOUT,
						WIPE_TYPE_FADEOUT, WIPE_FADE_WHITE,
						WIPE_FRAME, WIPE_DEF_SYNC, heap_id );

			Snd_BgmFadeOut( 0, WIPE_FRAME );
			Snd_SePlay( SE_OPED_VOICE3 );
		}
		(*seq)++;
		break;

	case 1:
		if( WIPE_SYS_EndCheck() )
		{
			OS_Printf("開会式終了。終了関数へ。");
			return TRUE;
		}
		break;

	default : GF_ASSERT(0);
	}

	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	TRUE
 */
//-----------------------------------------------------------------------------
static BOOL ENDING_Func_Init(PKTHLN_PTR work, u8 *seq)
{
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);

	switch( *seq )
	{
	case 0 :
		// 親なら通信データを設定
		if( PTFrameGetCurrentID(work) == COMM_PARENT_ID )
		{
			ED_SendShareData( work );
		}

		// フェードイン
		WIPE_SYS_Start(	WIPE_PATTERN_WMS, WIPE_TYPE_SHUTTERIN_DOWN,
				WIPE_TYPE_SHUTTERIN_DOWN, WIPE_FADE_BLACK,
				WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );

		(*seq)++;
		break;

	case 1 :
		if( WIPE_SYS_EndCheck() )
		{
			OS_Printf("閉会式画面出ましたよ\n");
			//シーケンスシフト
			PTFrame_SetNextFuncTblIdx(work, ENDING_SEQ_MAIN);
		}
		break;

	default : GF_ASSERT(0);
	}

	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	TRUE
 */
//-----------------------------------------------------------------------------
static BOOL ENDING_Func_Main(PKTHLN_PTR work, u8 *seq)
{
	enum
	{
		ED_SEQ_START,
		ED_SEQ_POKEBONUS_START,
		ED_SEQ_POKEBONUS_INIT,
		ED_SEQ_POKEBONUS,
		ED_SEQ_PRIZE_START,
		ED_SEQ_PRIZE,
		ED_SEQ_POINT_KING_START,
		ED_SEQ_POINT_KING,
		ED_SEQ_POINT_KING_END,
		ED_SEQ_EFPRIZE_START,
		ED_SEQ_EFPRIZE,
		ED_SEQ_ADD_EVT_SCORE_START,
		ED_SEQ_ADD_EVT_SCORE,
		ED_SEQ_CALC_SCORE,
		ED_SEQ_DRAW,
		ED_SEQ_FINAL_SCORE,
		ED_SEQ_SCORE_ANM_INIT,
		ED_SEQ_SCORE_ANM,
		ED_SEQ_MEDAL,
		ED_SEQ_BEST_RECORD,
		ED_SEQ_LAST_MSG,
		ED_SEQ_END,

		ED_SEQ_MEDAL_NONE,
	};

	int i;
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);
	BOOL bCommWait = FALSE;

	// ボード処理
	BoardCnt_Main( ptr->wkBoardCnt );
	PtcEffectCnt_Main( ptr->wkPtcCnt );

	// 通信同期処理
	if( PTFrame_GetGameType(work) == PKTHLN_GAME_COMM )
	{
		bCommWait = ED_CommMain( work );
	}

	//メッセージ駆動
	MSG_CNT_Main( ptr->MsgCnt );

	if( MSG_CNT_IsPrinting( ptr->MsgCnt ) == FALSE && bCommWait == FALSE )
	{
		WORDSET* WordSet = MSG_CNT_GetWordSet( ptr->MsgCnt );
		int code = MSG_ID_NONE;

		//シーケンス処理
		switch(ptr->Seq)
		{
		case ED_SEQ_START :
			//閉会式の言葉リクエスト
			code = msg_pkthln_ed_start;
			ptr->Seq = ED_SEQ_POKEBONUS_START;
			break;
		case ED_SEQ_POKEBONUS_START :
			code = msg_pkthln_ed_ability_01;
			ptr->Seq = ED_SEQ_POKEBONUS_INIT;
			break;
		case ED_SEQ_POKEBONUS_INIT :
			// ポケモンボーナス加点開始
			for( i=0; i<TEAM_NUM; i++ )
			{
				BoardCnt_StartAdd( ptr->wkBoardCnt, i, GetPokemonBonus( work, i ) );
			}
			ptr->Seq = ED_SEQ_POKEBONUS;
			/* fallthru */
		case ED_SEQ_POKEBONUS :
			// ポケモンボーナス
			if (ptr->TeamCnt >= TEAM_NUM)
			{
				code = msg_pkthln_ed_prize_01;
				ptr->TeamCnt = 0;
				ptr->Seq = ED_SEQ_PRIZE_START;
			}
			else
			{
				int score;
				code = msg_pkthln_ed_ability_02;
				score = GetPokemonBonus( work, ptr->TeamCnt );
				PrintTeamScore( work, ptr->TeamCnt, score );
				ptr->TeamCnt++;
			}
			break;
		case ED_SEQ_PRIZE_START :
			// ノーミスボーナス 開始チェック
			{
				// ノーミスポケモンの存在チェック
				if( CheckNoMissPokemonExist( work ) )
				{
					HOSAKA_PRINT("START NO MISS BONUS !\n");
					code = msg_pkthln_ed_prize_02;
					ptr->Seq = ED_SEQ_PRIZE;
				}
				else
				{
					// いなかった場合はスキップ
					code = msg_pkthln_ed_prize_04; // いませんでした
					ptr->Seq = ED_SEQ_POINT_KING_START;
				}
			}
			break;
		case ED_SEQ_PRIZE :
			// アニメ再生ウェイト
			if (CheckAnimeTask(ptr)){ break; }

			if (ptr->Cnt >= GetNomissCount(work) )
			{
				// ノーミスボーナス 終了
				code = msg_pkthln_ed_prize_05;
				ptr->TeamCnt = 0;
				ptr->PokeCnt = 0;
				ptr->Cnt = 0;
				ptr->Seq = ED_SEQ_POINT_KING_START;
			}
			else
			{
				// ノーミスポケモンの頭だし
				if( SearchAddBonus( work, &CheckNoMissPokemon, GetNoMissScore(ptr) ) )
				{
					code = msg_pkthln_ed_prize_03;
				}
			}
			break;
		case ED_SEQ_POINT_KING_START :
			// ポイント王
			OS_TPrintf("START POINT KING BONUS !\n");
			code = msg_pkthln_ed_prize_06;
			ptr->Seq = ED_SEQ_POINT_KING;
			break;
		case ED_SEQ_POINT_KING :
			// アニメ再生ウェイト
			if (CheckAnimeTask(ptr)){ break; }

			if (ptr->Cnt >= GetKingPointCount(work) )
			{
				//ポイント王 終了
				code = msg_pkthln_ed_prize_05;
				ptr->TeamCnt = 0;
				ptr->PokeCnt = 0;
				ptr->Cnt = 0;
				ptr->Seq = ED_SEQ_POINT_KING_END;
			}
			else
			{
				// ポイント王ポケモンの頭だし
				if( SearchAddBonus( work, &CheckPointKingPoke, GetKingPoint(ptr) ) )
				{
					code = msg_pkthln_ed_prize_07;
				}
			}
			break;
		case ED_SEQ_POINT_KING_END :
			if( GetEffortType(work) != EFFORT_NULL )
			{
				code = msg_pkthln_ed_efprize_01; ///< 努力賞の発表です
				ptr->Seq = ED_SEQ_EFPRIZE_START;
			}
			else
			{
				ptr->Seq = ED_SEQ_ADD_EVT_SCORE_START;	///< 丸々飛ばす
			}
			break;
		case ED_SEQ_EFPRIZE_START :
			// 努力賞 開始
			OS_TPrintf("START EFFORT BONUS ! EffortType=%d \n", GetEffortType(work) );
			code = msg_pkthln_ed_efprize_j + GetEffortType(work);	///< 賞の種類
			ptr->Seq = ED_SEQ_EFPRIZE;
			break;
		case ED_SEQ_EFPRIZE :
			// アニメ再生ウェイト
			if (CheckAnimeTask(ptr)){ break; }

			if (ptr->Cnt >= GetEffortPrizeCount(work) )
			{
				// 同着がいなければ終了
				code = msg_pkthln_ed_efprize_03; // 努力賞 以上です！
				ptr->TeamCnt = 0;
				ptr->PokeCnt = 0;
				ptr->Cnt = 0;
				ptr->Seq = ED_SEQ_ADD_EVT_SCORE_START;
			}
			else
			{
				// 努力賞取得ポケモンの頭だし
				if( SearchAddBonus( work, &CheckEffortPrizePoke, GetEffortPoint(ptr) ) )
				{
					code = msg_pkthln_ed_efprize_02;
				}
			}
			break;
		case ED_SEQ_ADD_EVT_SCORE_START :
			// 競技加点 開始
			code = msg_pkthln_ed_evtscore_01;
			ptr->Seq = ED_SEQ_ADD_EVT_SCORE;
			// ドラムロール開始
			Snd_BgmStop( Snd_NowBgmNoGet(), 16 );
			Snd_SePlay( SE_OPED_DRUM );
			break;
		case ED_SEQ_ADD_EVT_SCORE :
			if( BoardCnt_CheckEnd(ptr->wkBoardCnt) && ptr->NextAnmWait++ > EVT_SCORE_ADD_WAIT )
			{
				u8 EvtMax = ( PTFrame_GetGameType(work) == PKTHLN_GAME_ALONE ? ALONE_EVT_MAX : COMM_EVT_MAX );

				ptr->NextAnmWait = 0;

				if (ptr->Cnt >= EvtMax )
				{
					// 加点 終了
					ptr->Cnt = 0;
					ptr->Seq = ED_SEQ_CALC_SCORE;

#if 0 // PM_DEBUG
			// 強制同点
			if( sys.trg & PAD_BUTTON_DEBUG )
			{
				int i;
				for( i=0; i<TEAM_NUM; i++ )
				{
					ptr->wkBoardCnt->wkBoard[i].Score = (i<2) ? 999 : 998;
					ptr->wkBoardCnt->wkBoard[i].bMove = 1;
				}
				HOSAKA_PRINT("インチキ加算!\n");
			}
#endif
				}
				else
				{
					code = msg_pkthln_ed_evtscore_02;
					WORDSET_RegNum( WordSet, ptr->Cnt+1, 1, 0 );

					// 一気に全チーム加点
					for( i=0; i<TEAM_NUM; i++ )
					{
						int score = GetEventScore(work, i, ptr->Cnt);
						BoardCnt_StartAdd( ptr->wkBoardCnt, i, score );
						HOSAKA_PRINT("add evt score[%d]:%d->%d点\n",ptr->Cnt, i, score );
					}

					ptr->Cnt++;
				}
			}
			break;
		case ED_SEQ_CALC_SCORE :
			//競技結果計算

#ifdef PM_DEBUG
			// 強制同点終了待ち
			if(	BoardCnt_CheckEnd(ptr->wkBoardCnt) == FALSE )
			{
				break;
			}
#endif

			// 順位データを生成
			{
				u8 DrawWinPoint[TEAM_NUM];

				GetDrawWinPoint( work, DrawWinPoint );
				BoardCnt_CalcGrade(ptr->wkBoardCnt, ptr->Grade, DrawWinPoint );
			}

			// 同点判定
			if( ptr->Grade[0].Grade == ptr->Grade[1].Grade )
			{
				ptr->Seq = ED_SEQ_DRAW;
			}
			else
			{
				ptr->Seq = ED_SEQ_FINAL_SCORE;
			}
			break;

		case ED_SEQ_DRAW :
			code = msg_pkthln_ed_draw;

			Grade_SortDraw( ptr->Grade );

			// 同点演出、優勝者決定
			ptr->Seq = ED_SEQ_FINAL_SCORE;
			break;

		case ED_SEQ_FINAL_SCORE :
			// 総合スコア発表
			code = msg_pkthln_ed_score;
			{
				int score;

				// Winチームのスコア表示
				score = BoardCnt_GetScore(ptr->wkBoardCnt, ptr->Grade[0].NetID );
				WORDSET_RegNum( WordSet, score, 3, 0 );

				// 値を返す
				ED_SetSvSetData( work, ptr->wkBoardCnt );
			}
			ptr->Seq = ED_SEQ_SCORE_ANM_INIT;
			break;
		case ED_SEQ_SCORE_ANM_INIT :
			// BGをロード
			LoadWinBg( ptr->bgl, ptr->HeapID );
			ptr->Seq = ED_SEQ_SCORE_ANM;
			/* fallthru */

		case ED_SEQ_SCORE_ANM :
			{
				int WinTeamID = ptr->Grade[0].NetID;
				//優勝者発表メッセージリクエスト
				code = msg_pkthln_ed_rslt;

				// チーム名レジスト
				WORDSET_RegisterPlayerName( WordSet, 0, PTFrame_GetMyStatus(work, WinTeamID) );

				// 優勝チームポケグラ表示
				CATS_CreatePokegra(work, WinTeamID);
				// 紙ふぶき開始
				PtcEffectCnt_SetAutoAdd( ptr->wkPtcCnt, TRUE );

				// トレーナー正面を向く
				MANOBJ_TransAnimeSeq( ptr->cap, work, WinTeamID, POKE_DIR_DOWN, ptr->HeapID );
				CATS_ObjectAnimeSeqSetCap( ptr->cap[ WinTeamID ], 1 );	// ジャンプ！

				Snd_SeStopBySeqNo( SE_OPED_DRUM, 0 );
				Snd_SePlay( SE_OPED_VOICE10 );
				Snd_SePlay( SE_OPED_VOICE7	);

				Snd_BgmPlay( SEQ_GS_PT_VICTORY );
				// マスターコースの場合メダルなし
				if( ptr->CrsID == CRS_ID_MAS )
				{
					ptr->Seq = ED_SEQ_MEDAL_NONE;
				}
				else
				{
					ptr->Seq = ED_SEQ_MEDAL;
				}
			}
			break;
		case ED_SEQ_MEDAL_NONE :
			code = msg_pkthln_ed_mdl_03;
			WORDSET_RegisterPkthlnCourse( WordSet, 0, ptr->CrsID );
			ptr->Seq = ED_SEQ_LAST_MSG;	// 締めのメッセージへ
			break;
		case ED_SEQ_MEDAL :
			// メダル獲得開始
			code = msg_pkthln_ed_mdl_01_01;
			WORDSET_RegisterPlayerName( WordSet, 0, PTFrame_GetMyStatus(work, ptr->Grade[0].NetID) );

			//メダル表示
			{
				CATS_ObjectEnableCap( ptr->cap[ CAP_ID_MDL_HEAD ], TRUE );
				WORDSET_RegisterPkthlnMedal( WordSet, 1, GetMedalIdx( ptr->CrsID, 0 ) );

				// 二個目表示
				if(ptr->CrsID >= CRS_ID_SPD_JMP )
				{
					code = msg_pkthln_ed_mdl_01_02;
					CATS_ObjectEnableCap( ptr->cap[ CAP_ID_MDL_HEAD+1 ], TRUE );
					WORDSET_RegisterPkthlnMedal( WordSet, 2, GetMedalIdx( ptr->CrsID, 1 ) );
				}
			}
			ptr->Seq = ED_SEQ_BEST_RECORD;
			break;
		case ED_SEQ_BEST_RECORD :
			{
				u8 crsID = ptr->CrsID;
				// 非通信状態かつ優勝が自分ならレコード処理
				if( PTFrame_GetGameType( work ) == PKTHLN_GAME_ALONE && ptr->Grade[0].NetID == PTFrameGetCurrentID(work) )
				{
					SAVEDATA* sv;
					PKTHLN_SV_DATA_PTR pv;
					PKTH_COURSE* crs;

					GF_ASSERT( ptr->Grade[0].NetID == 0 );  ///< 自分が優勝した時しかこない

					sv = PTFrame_GetSaveData(work);
					pv = PkthlnSv_GetSaveData(sv);
					crs = PkthlnSv_GetCrsDataAlone(pv);

					if( crs[ crsID ].MaxScore < BoardCnt_GetScore(ptr->wkBoardCnt, ptr->Grade[0].NetID ) )
					{
						// レコード更新
						code = msg_pkthln_ed_mdl_02;
						WORDSET_RegisterPlayerName( WordSet, 0, PTFrame_GetMyStatus(work, ptr->Grade[0].NetID) );
						WORDSET_RegisterPkthlnCourse( WordSet, 1, crsID );
					}
				}
				else
				{
					code = msg_pkthln_ed_mdl_03;
					WORDSET_RegisterPkthlnCourse( WordSet, 0, crsID );
				}
			}
			ptr->Seq = ED_SEQ_LAST_MSG;
			break;
		case ED_SEQ_LAST_MSG :
			//締めのメッセージ
			code = msg_pkthln_ed_end;
			// 歓声END
			Snd_SeStopBySeqNo( SE_OPED_VOICE10, 120 );
			// 子機の終了フラグを立てる
			ptr->EndFlag = TRUE;

			ptr->Seq = ED_SEQ_END;
			break;
		case ED_SEQ_END :
			// 通信時は親機のEndFlagが立つのを待つ
			if( PTFrame_GetGameType(work) == PKTHLN_GAME_ALONE || ED_CheckEndFlag(work) )
			{
				//アニメタスクを終了させる
				if (CheckAnimeTask(ptr)){
					sys_FreeMemoryEz(ptr->TaskWork);
					TCB_Delete(ptr->Tcb);
				}
				MSG_CNT_PrintEnd( ptr->MsgCnt );
				//シーケンスシフト
				PTFrame_SetNextFuncTblIdx(work, ENDING_SEQ_END);
				return FALSE;
			}
			break;

		default : GF_ASSERT(0);
		}

		//メッセージ作成
		if( code != MSG_ID_NONE )
		{
			MSG_CNT_PrintMessage( ptr->MsgCnt, code );
			// メッセージシーケンスを進める
			ptr->MsgSeq++;
		}
	}

#ifdef PM_DEBUG
	if (sys.trg & PAD_BUTTON_X){
		// ワイプ状態を念のため解除
		WIPE_SYS_ExeEnd();
		//アニメタスクを終了させる
		if (CheckAnimeTask(ptr)){
			sys_FreeMemoryEz(ptr->TaskWork);
			TCB_Delete(ptr->Tcb);
		}
		MSG_CNT_PrintEnd( ptr->MsgCnt );
		Snd_SeStopBySeqNo( SE_OPED_VOICE10, 0 );
		//シーケンスシフト
		PTFrame_SetNextFuncTblIdx(work, ENDING_SEQ_END);
	}
#endif

	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	TRUE
 */
//-----------------------------------------------------------------------------
static BOOL ENDING_Func_End(PKTHLN_PTR work, u8 *seq)
{
	enum{ WIPE_FRAME = 30, };

	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);

	PtcEffectCnt_Main( ptr->wkPtcCnt );

	// ホワイトアウト
	switch( *seq )
	{
	case 0:
		{
			HEAPID heap_id = PTFrame_GetHeapID( work );

			WIPE_SYS_Start(	WIPE_PATTERN_WMS, WIPE_TYPE_FADEOUT,
						WIPE_TYPE_FADEOUT, WIPE_FADE_WHITE,
						WIPE_FRAME, WIPE_DEF_SYNC, heap_id );

			Snd_BgmFadeOut( 0, WIPE_FRAME );
		}
		(*seq)++;
		break;

	case 1:
		if( WIPE_SYS_EndCheck() )
		{
			OS_Printf("閉会式終了。終了関数へ。");
			return TRUE;
		}
		break;

	default : GF_ASSERT(0);
	}

	return FALSE;
}



//--------------------------------------------------------------------------------------------
/**
 * アニメタスク	TCB
 *
 * @param	tcb			TCB
 * @param	work		ワーク
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void AnimeTask(TCB_PTR tcb, void* work)
{
	ANIME_TASK_WORK *task_work = work;
	POKE_ACT_PTR poke_act = task_work->PokeActPtr;

	switch(task_work->Seq){
	case 0:
		PokeAct_SetDir(poke_act, POKE_DIR_DOWN);
		PokeAct_SetAnm(poke_act, ANM_TYPE_THROW);
		task_work->Seq++;
		break;
	case 1:
		if( task_work->Timer++ > ANM_WAIT )
		{
			task_work->Seq++;
		}
		break;
	case 2:
		// アニメ、鳴き声終了待ち
		if( PokeAct_AnmActiveCheck( poke_act ) == FALSE && Snd_PMVoicePlayCheck() == FALSE )
		{
			//アニメ終了
			PokeAct_SetDir(poke_act, POKE_DIR_UP);
			PokeAct_SetAnm(poke_act, ANM_TYPE_WALK);
			*task_work->AnimeFlg = FALSE;
			sys_FreeMemoryEz(work);
			TCB_Delete(tcb);
		}
		break;
	default : GF_ASSERT( 0 );
	}
}

//--------------------------------------------------------------------------------------------
/**
 * アニメタスクのセットアップ
 *
 * @param	per			開会式管理ポインタ
 * @param	inIndex		インデックス
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetAnimeTask(OPENING_PTR ptr, const u8 inIndex)
{
	POKE_ACT_PTR poke_act;

	//ワーク作成
	ANIME_TASK_WORK *work = sys_AllocMemoryLo(ptr->HeapID, sizeof(ANIME_TASK_WORK));
	//メモリクリア
	MI_CpuClear8( work, sizeof(ANIME_TASK_WORK));
	ptr->TaskWork = work;
	//アクターポインタをセット
	work->PokeActPtr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, inIndex);
	//アニメフラグを成立させ、タスクにポインタをセット
	ptr->AnimeFlg = TRUE;
	work->AnimeFlg = &ptr->AnimeFlg;

	//タスク生成
	ptr->Tcb = TCB_Add(AnimeTask, work, 1);
}

//-----------------------------------------------------------------------------
/**
 *	@brief	TCBアニメが再生中かチェック
 *
 *	@param	ptr
 *
 *	@retval	TRUE:再生中
 */
//-----------------------------------------------------------------------------
static BOOL CheckAnimeTask(OPENING_PTR ptr)
{
	return ptr->AnimeFlg;
}

//----------------------------------------------------------------------------
/**
 *	@brief	RECT_HIT_TBLを登録
 *
 *	@param	*rect		矩形データポインタ
 *	@param	x			X
 *	@param	y			Y
 *	@param	sizx		X幅
 *	@param	sizy		Y幅
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void SetPokeRectHitTable(RECT_HIT_TBL *rect, int x, int y, int sizx, int sizy)
{
  rect->rect.top    = y - sizy / 2;
  rect->rect.left   = x - sizx / 2;
  rect->rect.bottom = y + sizy / 2;
  rect->rect.right  = x + sizx / 2;
}


//--------------------------------------------------------------------------------------------
/**
 * @brief	BG初期化
 * @param	*ini		BGL
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void BgInit(GF_BGL_INI * ini)
{
  {	/* BG SYSTEM */
    GF_BGL_SYS_HEADER BGsys_data = {
      GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BGMODE_0, GX_BG0_AS_2D,
    };
    GF_BGL_InitBG( &BGsys_data );
  }

  //メイン
  {	/* MAIN DISP BG0 */
    GF_BGL_BGCNT_HEADER MBg0_Data = {
      0, 0, 0x800, 0,
      GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      GX_BG_SCRBASE_0xe000, GX_BG_CHARBASE_0x00000,
      GX_BG_EXTPLTT_01, 3, 0, 0, FALSE
    };
    GF_BGL_BGControlSet( ini, GF_BGL_FRAME0_M, &MBg0_Data, GF_BGL_MODE_TEXT );
    GF_BGL_ScrClear( ini, GF_BGL_FRAME0_M );
    GF_BGL_CharFill( ini, GF_BGL_FRAME1_M, 0, 1, 0 );
  }

  {	/* MAIN DISP BG1 */
    GF_BGL_BGCNT_HEADER MBg1_Data = {
      0, 0, 0x800, 0,
      GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      GX_BG_SCRBASE_0xd800, GX_BG_CHARBASE_0x04000,
      GX_BG_EXTPLTT_01, 0, 0, 0, FALSE
    };
    GF_BGL_BGControlSet( ini, GF_BGL_FRAME1_M, &MBg1_Data, GF_BGL_MODE_TEXT );
    GF_BGL_ScrClear( ini, GF_BGL_FRAME1_M );
    GF_BGL_CharFill( ini, GF_BGL_FRAME1_M, 0, 1, 0 );
  }

  //サブ
  {	/* SUB DISP BG0 TEXT */
    GF_BGL_BGCNT_HEADER SBg0_Data = {
      0, 0, 0x800, 0,
      GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      GX_BG_SCRBASE_0xe000, GX_BG_CHARBASE_0x00000,
      GX_BG_EXTPLTT_01, 0, 0, 0, FALSE
    };
    GF_BGL_BGControlSet( ini, GF_BGL_FRAME0_S, &SBg0_Data, GF_BGL_MODE_TEXT );
    GF_BGL_ScrClear( ini, GF_BGL_FRAME0_S );
  }
  {	/* SUB DISP BG1 BASE */
    GF_BGL_BGCNT_HEADER SBg1_Data = {
      0, 0, 0x800, 0,
      GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      GX_BG_SCRBASE_0xf000, GX_BG_CHARBASE_0x08000,
      GX_BG_EXTPLTT_01, 3, 0, 0, FALSE
    };
    GF_BGL_BGControlSet( ini, GF_BGL_FRAME1_S, &SBg1_Data, GF_BGL_MODE_TEXT );
    GF_BGL_ScrClear( ini, GF_BGL_FRAME1_S );
  }
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	グラフィックセット
 * @param	ini			bgl
 * @param	inHeapID	ヒープID
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetGraphic(GF_BGL_INI * ini, const int inHeapID)
{
	//キャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_OPED, 3,
						ini, GF_BGL_FRAME0_M, 0, 0, FALSE, inHeapID);
	//キャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_OPED, 1,
						ini, GF_BGL_FRAME1_S, 0, 0, FALSE, inHeapID);
	//スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_OPED, 6,
						ini, GF_BGL_FRAME0_M, 0, 0, FALSE, inHeapID);
	//スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_OPED, 4,
						ini, GF_BGL_FRAME1_S, 0, 0, FALSE, inHeapID);
	//パレット
	ArcUtil_PalSet( ARC_PKTHEV_OPED, 0,
						PALTYPE_MAIN_BG, 0, 0, inHeapID );
	//パレット
	ArcUtil_PalSet( ARC_PKTHEV_OPED, 0,
						PALTYPE_SUB_BG, 0, 0, inHeapID );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケグラのBGをロード 勝利用
 *
 *	@param	ini
 *	@param	int inHeapID
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void LoadWinBg(GF_BGL_INI* ini, const int inHeapID)
{
	ArcUtil_BgCharSet(ARC_PKTHEV_OPED, 3, ini, GF_BGL_FRAME1_M, 0, 0, FALSE, inHeapID);
	ArcUtil_ScrnSet(ARC_PKTHEV_OPED, 7, ini, GF_BGL_FRAME1_M, 0, 0, FALSE, inHeapID);
}

//-----------------------------------------------------------------------------
/**
 *	@brief	CATSシステム生成
 *
 *	@param	OPENING_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_Create( OPENING_PTR ptr )
{
	TCATS_RESOURCE_NUM_LIST crnl = { CHR_ID_MAX, PAL_ID_MAX, CEL_ID_MAX, ANM_ID_MAX, 0 };

	TCATS_OAM_INIT	coi = {
		0, 126,
		0, 32,
		1, 126,
		0, 32,
	};

	TCATS_CHAR_MANAGER_MAKE ccmm = {
		0,	// dummy
		1024*256,
		1024*16,
		GX_OBJVRAMMODE_CHAR_1D_256K,
		GX_OBJVRAMMODE_CHAR_1D_64K,
	};
	ccmm.num = OBJ_ID_MAX;

	ptr->csp = CATS_AllocMemory( ptr->HeapID );
	ptr->crp = CATS_ResourceCreate( ptr->csp );

//	CATS_RenderUseSet( ptr->csp, CATS_RENDER_USE_OFF );

	CATS_SystemInit( ptr->csp, &coi, &ccmm, 32 );
	CATS_ClactSetInit( ptr->csp, ptr->crp, OBJ_ID_MAX);
	CATS_ResourceManagerInit( ptr->csp, ptr->crp, &crnl );

	//サブサーフェースの距離を設定
	CLACT_U_SetSubSurfaceMatrix( CATS_EasyRenderGet( ptr->csp ), 0, CATS_DISTANCE );

}

//-----------------------------------------------------------------------------
/**
 *	@brief	CATSシステム開放
 *
 *	@param	OPENING_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_Delete( OPENING_PTR ptr )
{
	u8 i;
	for( i=0; i<CAP_ID_MAX; i++ )
	{
		if( ptr->cap[i] != NULL )
		{
			CATS_ActorPointerDelete_S( ptr->cap[i] );
			ptr->cap[i] = NULL;
		}
	}

	CATS_ResourceDestructor_S( ptr->csp, ptr->crp );
	CATS_FreeMemory( ptr->csp );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	CATSにマップモデル表示用アクターを追加（この時点ではダミー絵）
 *
 *	@param	OPENING_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_AddMapModel( OPENING_PTR ptr )
{
	TCATS_OBJECT_ADD_PARAM_S prm = {0};
	int i;

	for( i=0; i<CAP_ID_MMO_MAX; i++ )
	{
		int cap_idx = i;

		prm.id[0] = CHR_ID_S_MMO_HEAD + i;
		prm.id[1] = PAL_ID_S_MMO_HEAD + i;
		prm.id[2] = CEL_ID_MMO;
		prm.id[3] = ANM_ID_MMO;
		prm.d_area = NNS_G2D_VRAM_TYPE_2DSUB;
		prm.bg_pri = 1;
		prm.pri = 1;
		prm.x = 32 + i * 64;
		prm.y = 136;

		// 司会者
		if( cap_idx == CAP_ID_MMO_TALKER )
		{
			prm.x = 128;
			prm.y = 112;
		}

		ptr->cap[ cap_idx ] = CATS_ObjectAdd_S_SubDistance( ptr->csp, ptr->crp, &prm, CATS_DISTANCE );
		CATS_ObjectAutoAnimeSetCap( ptr->cap[ cap_idx ], TRUE );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	OPENING_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_AddScoreBoard( OPENING_PTR ptr )
{
	TCATS_OBJECT_ADD_PARAM_S prm = {0};
	int i;
	int cnt;

	for( i=0; i<BOARD_NUM; i++ )
	{
		int cap_idx = CAP_ID_BOARD_HEAD + (i * BOARD_CAP_NUM);

		prm.id[0] = CHR_ID_S_OPED;
		prm.id[1] = PAL_ID_S_OPED;
		prm.id[2] = CEL_ID_S_OPED;
		prm.id[3] = ANM_ID_S_OPED;
		prm.d_area = NNS_G2D_VRAM_TYPE_2DSUB;
		prm.bg_pri = 1;
		prm.pri = 2;
		prm.x = 32 + ( i * 64 ) ;
		prm.y = 72;
		prm.anm = 0;
		prm.pal = 1 + i;

		// ベースOBJ
		ptr->cap[ cap_idx ] = CATS_ObjectAdd_S_SubDistance( ptr->csp, ptr->crp, &prm, CATS_DISTANCE );
		CATS_ObjectAutoAnimeSetCap( ptr->cap[ cap_idx ], TRUE );

		// スコア用値
		prm.pal = 0;
		prm.bg_pri = 1;
		prm.pri = 1;
		prm.x -= 16;
		prm.anm = 1; /// とりあえず[0]
		for( cnt = 0; cnt < BOARD_SCORE_NUM; cnt ++ )
		{
			int scr_cap_idx = cap_idx + 1 + cnt;
			ptr->cap[ scr_cap_idx ] = CATS_ObjectAdd_S_SubDistance( ptr->csp, ptr->crp, &prm, CATS_DISTANCE );
			CATS_ObjectAutoAnimeSetCap( ptr->cap[ scr_cap_idx ], TRUE );
			prm.x += 16;
		}
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	OPENING_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_AddPokegra( OPENING_PTR ptr )
{
	TCATS_OBJECT_ADD_PARAM_S prm = {0};
	int i;
	int cnt;

	for( i=0; i<ENTRY_MAX; i++ )
	{
		int cap_idx = CAP_ID_POKEGRA_HEAD + i;

		prm.id[0] = CHR_ID_M_POKEGRA_0 + i;
		prm.id[1] = PAL_ID_M_OPED;
		prm.id[2] = CEL_ID_POKEGRA;
		prm.id[3] = ANM_ID_POKEGRA;
		prm.d_area = NNS_G2D_VRAM_TYPE_2DMAIN;
		prm.x = 6*8 + 10*8 * i;
		prm.y = GX_LCD_SIZE_Y / 2 + 8*2;
		prm.bg_pri = 0;
		prm.pri = 1;

		ptr->cap[ cap_idx ] = CATS_ObjectAdd_S_SubDistance( ptr->csp, ptr->crp, &prm, CATS_DISTANCE );
		CATS_ObjectPaletteSetCap( ptr->cap[ cap_idx ], 2 + i * 3 ); // 参照位置をずらす
		CATS_ObjectEnableCap( ptr->cap[ cap_idx ], FALSE ); // 非表示にしておく
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	OPENING_PTR ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_AddMedal( OPENING_PTR ptr )
{
	TCATS_OBJECT_ADD_PARAM_S prm = {0};
	int i;

	for(i=0; i<MEDAL_NUM; i++)
	{
		int cap_idx = CAP_ID_MDL_HEAD + i;

		prm.id[0] = CHR_ID_M_MDL_0 + i;
		prm.id[1] = PAL_ID_M_MDL_0 + i;
		prm.id[2] = CEL_ID_M_MDL;
		prm.id[3] = ANM_ID_M_MDL;
		prm.d_area = NNS_G2D_VRAM_TYPE_2DMAIN;
		prm.bg_pri = 0;
		prm.pri = 2;
		prm.x = 96 + 4 + i * 64-4;
		prm.y = 56;

		// 非通信コースは１つだけなので真ん中に表示
		if( ptr->CrsID < CRS_ID_SPD_JMP )
		{
			prm.x = 128;
		}

		ptr->cap[ cap_idx ] = CATS_ObjectAdd_S_SubDistance( ptr->csp, ptr->crp, &prm, CATS_DISTANCE );
		CATS_ObjectAutoAnimeSetCap( ptr->cap[ cap_idx ], TRUE );
		CATS_ObjectEnableCap( ptr->cap[ cap_idx ], FALSE ); // 非表示にしておく
	}
}


//-----------------------------------------------------------------------------
/**
 *	@brief	優勝チームのポケグラを展開
 *
 *	@param	PKTHLN_PTR ptr
 *	@param	teamIdx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_TransPokegra( PKTHLN_PTR work, u8 TeamIdx )
{
	int i;
	OPENING_PTR ptr;
	POKETHLON_ENTRY_DATA* pEnt;
	COMMON_PLAYER_DATA* cmn_data;
	BOOL b_npc;

	ptr = PTFrame_GetEventWorkPtr(work);
	pEnt= PTFrame_GetEntryDataPtrByID( work, TeamIdx );

	cmn_data = PTFrame_GetCmnPlayerDataPtrByID( work, TeamIdx );
	b_npc = (cmn_data->PersonCode > 0);

	for( i=0; i<ENTRY_MAX; i++ )
	{
		int cap_idx = CAP_ID_POKEGRA_HEAD + i;
		MONS_INFO MonsInfo;

		PTFrame_SetMonsInfo( work, TeamIdx, i, &MonsInfo );

#if 0
		// NPCの場合は個体乱数0からキメウチで性別を決定
		if( b_npc )
		{
			mdat.Sex = PokeSexGetMonsNo( mdat.MonsNo, 0 );
		}
#endif

		// キャラだけ転送
		CATS_PokeGraTransEx( ptr->cap[ cap_idx ], &MonsInfo, TRUE, FALSE, ptr->HeapID, FALSE );

		// パレット転送
		{
			SOFT_SPRITE_ARC ssa;
			void* pltt_buf;
			NNSG2dPaletteData * pd;
			MONS_INFO* p_mons = &MonsInfo;

			// -- アーカイブデータ取得(ソフトウェアスプライト用）
			PokeGraArcDataGet( &ssa, p_mons->MonsNo, p_mons->Sex, PARA_FRONT, p_mons->Rare, p_mons->Form, p_mons->PsnlRnd );
			pltt_buf = ArcUtil_PalDataGet( ssa.arc_no, ssa.index_pal, &pd, ptr->HeapID );

			PokeAct_ChangePalette( ptr->PokeActCntPtr, 1 + i * 3, NNS_G2D_VRAM_TYPE_2DMAIN, pd->pRawData );

			sys_FreeMemoryEz( pltt_buf );
		}
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	トレーナー用ダーミーリソースを展開
 *
 *	@param	CATS_SYS_PTR csp
 *	@param	crp
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_LoadRes( PKTHLN_PTR work )
{
	u8 i;

	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);
	CATS_SYS_PTR csp = ptr->csp;
	CATS_RES_PTR crp = ptr->crp;

	u32 cgr_idx = NARC_pkthev_oped_obj_dmy_lz_ncgr;
	u32 cell_idx = NARC_pkthev_oped_obj_dmy_lz_ncer;
	u32 anm_idx = NARC_pkthev_oped_obj_dmy_lz_nanr;
	u32 pal_idx = NARC_pkthev_oped_obj_dmy_nclr;

	// 主人公＋司会用のダミーファイルを読み込み
	for( i=0; i<CAP_ID_MMO_MAX; i++ )
	{
		CATS_LoadResourceCharArc(  csp, crp, ARC_PKTHEV_OPED, cgr_idx, TRUE, NNS_G2D_VRAM_TYPE_2DSUB, CHR_ID_S_MMO_HEAD + i );
		CATS_LoadResourcePlttArc( csp, crp, ARC_PKTHEV_OPED, pal_idx, 0, 1, NNS_G2D_VRAM_TYPE_2DSUB, PAL_ID_S_MMO_HEAD + i );
	}

	CATS_LoadResourceCellArc( csp, crp, ARC_PKTHEV_OPED, cell_idx, TRUE, CEL_ID_MMO );
	CATS_LoadResourceCellAnmArc( csp, crp, ARC_PKTHEV_OPED, anm_idx, TRUE, ANM_ID_MMO );

	// このシーン用のOBJを読み込み
	pal_idx = NARC_pkthev_oped_obj_oped_nclr;
	cgr_idx = NARC_pkthev_oped_obj_oped_lz_ncgr;
	cell_idx = NARC_pkthev_oped_obj_oped_lz_ncer;
	anm_idx = NARC_pkthev_oped_obj_oped_lz_nanr;
	CATS_LoadResourceCharArc(		csp, crp, ARC_PKTHEV_OPED, cgr_idx,	TRUE, NNS_G2D_VRAM_TYPE_2DSUB, CHR_ID_S_OPED );
	CATS_LoadResourcePlttArc(		csp, crp, ARC_PKTHEV_OPED, pal_idx, 0, 5, NNS_G2D_VRAM_TYPE_2DSUB, PAL_ID_S_OPED );
	CATS_LoadResourceCellArc(		csp, crp, ARC_PKTHEV_OPED, cell_idx,	TRUE, CEL_ID_S_OPED );
	CATS_LoadResourceCellAnmArc(	csp, crp, ARC_PKTHEV_OPED, anm_idx,		TRUE, ANM_ID_S_OPED );

	//---------------------------------------------------------------
	// Main LCD
	//---------------------------------------------------------------

	// ポケグラ リソースロード
	CATS_LoadResPokegra( ptr );

	pal_idx = NARC_pkthev_oped_obj_oped_nclr;
	cgr_idx = NARC_pkthev_oped_obj_ed_d_lz_ncgr;
	cell_idx = NARC_pkthev_oped_obj_ed_d_lz_ncer;
	anm_idx = NARC_pkthev_oped_obj_ed_d_lz_nanr;
	CATS_LoadResourceCharArc( csp, crp, ARC_PKTHEV_OPED, cgr_idx,	TRUE, NNS_G2D_VRAM_TYPE_2DMAIN, CHR_ID_M_OPED );
	CATS_LoadResourcePlttArc( csp, crp, ARC_PKTHEV_OPED, pal_idx, 0, 1, NNS_G2D_VRAM_TYPE_2DMAIN, PAL_ID_M_OPED );
	CATS_LoadResourceCellArc( csp, crp, ARC_PKTHEV_OPED, cell_idx,	TRUE, CEL_ID_M_OPED );
	CATS_LoadResourceCellAnmArc( csp, crp, ARC_PKTHEV_OPED, anm_idx, TRUE, ANM_ID_M_OPED );

	// メダル リソースロード
	{
		u8 crsID = ptr->CrsID;

		pal_idx = NARC_pkthev_oped_medal_256k_01_nclr;
		cgr_idx = NARC_pkthev_oped_medal_256k_01_lz_ncgr;

		CATS_LoadResourcePlttArc(
				csp, crp, ARC_PKTHEV_OPED, pal_idx + GetMedalIdx( crsID, 0 ),
				0, 1, NNS_G2D_VRAM_TYPE_2DMAIN, PAL_ID_M_MDL_0 );

		CATS_LoadResourcePlttArc(
				csp, crp, ARC_PKTHEV_OPED, pal_idx + GetMedalIdx( crsID, 1 ),
				0, 1, NNS_G2D_VRAM_TYPE_2DMAIN, PAL_ID_M_MDL_1 );

		CATS_LoadResourceCharArc(
				csp, crp, ARC_PKTHEV_OPED, cgr_idx + GetMedalIdx( crsID, 0 ),
				TRUE, NNS_G2D_VRAM_TYPE_2DMAIN, CHR_ID_M_MDL_0 );

		CATS_LoadResourceCharArc(
				csp, crp, ARC_PKTHEV_OPED, cgr_idx + GetMedalIdx( crsID, 1 ),
				TRUE, NNS_G2D_VRAM_TYPE_2DMAIN, CHR_ID_M_MDL_1 );

		CATS_LoadResourceCellArc( csp, crp, ARC_PKTHEV_OPED, NARC_pkthev_oped_medal_256k_main_lz_ncer, TRUE, CEL_ID_M_MDL );
		CATS_LoadResourceCellAnmArc( csp, crp, ARC_PKTHEV_OPED, NARC_pkthev_oped_medal_256k_main_lz_nanr, TRUE, ANM_ID_M_MDL );
	}

}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケグラ用リソースを読み込み
 *
 *	@param	ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_LoadResPokegra(OPENING_PTR ptr)
{
	int i;
	CATS_SYS_PTR csp = ptr->csp;
	CATS_RES_PTR crp = ptr->crp;
	NNS_G2D_VRAM_TYPE vram_type = NNS_G2D_VRAM_TYPE_2DMAIN;
	int pltt_pos;

	for( i=0; i<ENTRY_MAX; i++ )
	{
		CATS_LoadResourceCharArc(
				csp, crp, ARC_PKTHEV_OPED, NARC_pkthev_oped_pokegra256_dmy_lz_ncgr,
				TRUE, vram_type, CHR_ID_M_POKEGRA_0 + i );
	}

	CATS_LoadResourceCellArc( csp, crp, ARC_PKTHEV_OPED, NARC_pkthev_oped_pokegra256_dmy_lz_ncer, TRUE, CEL_ID_POKEGRA );
	CATS_LoadResourceCellAnmArc( csp, crp, ARC_PKTHEV_OPED, NARC_pkthev_oped_pokegra256_dmy_lz_nanr, TRUE, ANM_ID_POKEGRA );
}

//----------------------------------------------------------------------------
/**
 *	@brief	ポケグラを生成
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void CATS_CreatePokegra( PKTHLN_PTR work, u8 WinTeamID )
{
	int i;
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);

	// OAM確保のため、隠れるOBJをENABLEにしておく
	for(i=0; i<TEAM_NUM; i++)
	{
		POKE_ACT_PTR poke_act_ptr = PokeAct_GetPokeActPtr( ptr->PokeActCntPtr, 1 + i * ENTRY_MAX );
		POKE_ACT_PTR poke_act_ptr2 = PokeAct_GetPokeActPtr( ptr->PokeActCntPtr, 2 + i * ENTRY_MAX );
		PokeAct_DispCnt(poke_act_ptr, FALSE);	//非表示
		PokeAct_DispCnt(poke_act_ptr2, FALSE);	//非表示
	}

	CATS_TransPokegra( work, WinTeamID );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	人物OBJ：初期化
 *
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void MANOBJ_Setup(PKTHLN_PTR work)
{
	int i;
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);

	for( i=0; i<CAP_ID_MMO_MAX; i++ )
	{
		int player_num = PTFrame_GetPlayerNum(work);
		u32 tex_idx;

		if( i == CAP_ID_MMO_TALKER )
		{
			// 司会者描画
			tex_idx = CATS_GetMapModelTexIdx( 2 );
			CATS_MapModelDraw( ptr->cap[i], tex_idx, TEX_ASEQ_NPC_FRONT, ptr->HeapID );
		}
		// プレイヤー描画
		else if( i < player_num )
		{
			CATS_HeroDraw( ptr->cap, work, i, TEX_ASEQ_HERO_BACK );
		}
		// NPC描画
		else
		{
			COMMON_PLAYER_DATA* cmn_data;
			int obj_code;
			int tex_idx;

			cmn_data = PTFrame_GetCmnPlayerDataPtrByID( work, i );
			obj_code = PTFrame_GetNpcObjCode( cmn_data->PersonCode );
			tex_idx = PTConv_NpcObjCode( obj_code );
			CATS_MapModelDraw( ptr->cap[i], tex_idx , TEX_ASEQ_NPC_BACK, ptr->HeapID );
		}
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	人物OBJ：向き指定
 *
 *	@param	CATS_ACT_PTR* ppCap
 *	@param	PKTHLN_PTR work
 *	@param	NetID
 *	@param	poke_dir
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void MANOBJ_TransAnimeSeq( CATS_ACT_PTR* ppCap, PKTHLN_PTR work, int NetID, int poke_dir, HEAPID HeapID )
{
	COMMON_PLAYER_DATA* cmn_data;
	BOOL b_npc;
	int animeseq;

	cmn_data = PTFrame_GetCmnPlayerDataPtrByID( work, NetID );
	b_npc = (cmn_data->PersonCode > 0);

	switch( poke_dir )
	{
		case POKE_DIR_UP :
			animeseq = b_npc ? TEX_ASEQ_NPC_BACK : TEX_ASEQ_HERO_BACK;
			break;
		case POKE_DIR_DOWN :
			animeseq = b_npc ? TEX_ASEQ_NPC_FRONT : TEX_ASEQ_HERO_FRONT;
			break;

		default : GF_ASSERT(0);
	}

	// 転送
	if( b_npc )
	{
		int obj_code;
		int tex_idx;

		cmn_data = PTFrame_GetCmnPlayerDataPtrByID( work, NetID );
		obj_code = PTFrame_GetNpcObjCode( cmn_data->PersonCode );
		tex_idx = PTConv_NpcObjCode( obj_code );
		CATS_MapModelDraw( ppCap[NetID], tex_idx , animeseq, HeapID );

		HOSAKA_PRINT("tex_idx : %d \n", tex_idx);
	}
	else
	{
		CATS_HeroDraw( ppCap, work, NetID, animeseq );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	HEAPID HeapID
 *	@param	ppCap
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOARD_CNT_WORK* BoardCnt_Create( HEAPID HeapID, CATS_ACT_PTR* ppCap )
{
	int i;
	BOARD_CNT_WORK* cnt;

	// Alloc
	cnt = sys_AllocMemory( HeapID, sizeof(BOARD_CNT_WORK) );
	MI_CpuClear8( cnt, sizeof(BOARD_CNT_WORK) );

	// CAPのコピー
	for( i=0; i<BOARD_NUM; i++ )
	{
		int j;
		int capIdx;
		BOARD_WORK* wk;

		wk = &cnt->wkBoard[i];
		capIdx = CAP_ID_BOARD_HEAD + (i * BOARD_CAP_NUM);

		for(j=0; j<BOARD_CAP_NUM; j++ )
		{
			wk->Cap[j] = ppCap[ capIdx + j ];
		}
	}

	return cnt;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	スコアボード管理モジュール 削除
 *
 *	@param	BOARD_CNT_WORK* wk
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void BoardCnt_Delete( BOARD_CNT_WORK* wk )
{
	sys_FreeMemoryEz( wk );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	スコアボード管理モジュール メイン処理
 *
 *	@param	BOARD_CNT_WORK* wk
 *
 *	@retval	none
 */
//-----------------------------------------------------------------------------
static void BoardCnt_Main( BOARD_CNT_WORK* wk )
{
	int i;
	for( i=0; i<BOARD_NUM; i++ )
	{
		Board_Main( &wk->wkBoard[i] );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	スコアボード 終了チェック
 *
 *	@param	BOARD_CNT_WORK* wk
 *
 *	@retval	TRUE:終了
 */
//-----------------------------------------------------------------------------
static BOOL BoardCnt_CheckEnd( BOARD_CNT_WORK* wk )
{
	int i;
	BOOL bCheckEnd = TRUE;

	for( i=0; i<BOARD_NUM; i++ )
	{
		// 一個でも処理中のものがあったらFALSE
		if( Board_CheckEnd( &wk->wkBoard[i] ) == FALSE ){ bCheckEnd = FALSE; }
	}
	return bCheckEnd;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	スコアボード 加算開始
 *
 *	@param	BOARD_CNT_WORK* wk
 *	@param	idx
 *	@param	score
 *
 *	@retval	none
 */
//-----------------------------------------------------------------------------
static void BoardCnt_StartAdd( BOARD_CNT_WORK* wk, u8 idx, u16 add )
{
	if( add > 0 )
	{
		Board_StartAdd( &wk->wkBoard[ idx ], add );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	スコアボード　累計点取得
 *
 *	@param	BOARD_CNT_WORK* wk
 *	@param	idx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u32 BoardCnt_GetScore( BOARD_CNT_WORK* wk, u8 idx )
{
	return wk->wkBoard[ idx ].Score;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ソート関数
 *
 *	@param	void* elem1
 *	@param	elem2
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static s32 GradeSortByScore( void* elem1, void* elem2 )
{
	GRADE_DATA* p1 = (GRADE_DATA*)elem1;
	GRADE_DATA* p2 = (GRADE_DATA*)elem2;

	if( p1->Score == p2->Score ) {
		return 0;
	} else if( p1->Score < p2->Score ) {
		return 1;
	} else {
		return -1;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	順位計算
 *
 *	@param	work	スロンポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void BoardCnt_CalcGrade(BOARD_CNT_WORK* wk, GRADE_DATA* pGradeData, u8* pDrawWinPoint )
{
	int i;
	int grade_cnt = 0;

	// データ生成
	for(i=0; i<TEAM_NUM; i++)
	{
		pGradeData[i].NetID = i;
		pGradeData[i].Score = BoardCnt_GetScore( wk, i );
		pGradeData[i].DrawWinPoint = pDrawWinPoint[i];
	}

	// ソート
	MATH_QSort( (void*)pGradeData, TEAM_NUM, sizeof(GRADE_DATA), GradeSortByScore, NULL );

	// 順位計算
	for(i=0; i<TEAM_NUM; i++ )
	{
		pGradeData[i].Grade = grade_cnt; // 順位を保持

		if( i != TEAM_NUM-1 )
		{
			// 次の項目と比較して、同点でなければ順位を更新
			if( pGradeData[i].Score != pGradeData[i+1].Score )
			{
				grade_cnt = i+1;
			}
		}
	}


}

//-----------------------------------------------------------------------------
/**
 *	@brief	スコアボード メイン処理
 *
 *	@param	BOARD_WORK* wk
 *
 *	@retval	none
 */
//-----------------------------------------------------------------------------
static void Board_Main( BOARD_WORK* wk )
{
	if( wk->bMove == FALSE ){ return; }

	wk->ScoreView = MATH_CLAMP( wk->ScoreView + 1, 0, BD_SCORE_MAX );

	//終了していたら
	if( Snd_SePlayCheck(SE_OPED_SCORE) == FALSE ){
		//再度再生
		Snd_SePlay( SE_OPED_SCORE );
	}

	// OBJ反映
	{
		u16 fig[BOARD_SCORE_NUM];
		fig[0] = UTIL_GetFigreAppoint( wk->ScoreView, 3 );
		fig[1] = UTIL_GetFigreAppoint( wk->ScoreView, 2 );
		fig[2] = UTIL_GetFigreAppoint( wk->ScoreView, 1 );
		CATS_ObjectAnimeSeqSetCap( wk->Cap[BDCAP_ID_NUM_0], 1 + fig[0] );
		CATS_ObjectAnimeSeqSetCap( wk->Cap[BDCAP_ID_NUM_1], 1 + fig[1] );
		CATS_ObjectAnimeSeqSetCap( wk->Cap[BDCAP_ID_NUM_2], 1 + fig[2] );
	}

	// 座標移動
	// 黒枠は48ドット、999(最高得点)/48 = 20ぐらい
	if( wk->ScoreView % 20 == 0 )
	{
		int i;
		for( i=0; i<BOARD_CAP_NUM; i++ )
		{
			CATS_ObjectPosMoveCap( wk->Cap[i], 0, -1 );
		}
	}

	// 終了判定
	if( wk->ScoreView >= wk->Score ){ wk->bMove = FALSE; }

}

//-----------------------------------------------------------------------------
/**
 *	@brief	スコアボード 移動終了チェック
 *
 *	@param	BOARD_WORK* wk
 *
 *	@retval	TRUE	移動終了
 */
//-----------------------------------------------------------------------------
static BOOL Board_CheckEnd( BOARD_WORK* wk )
{
	return ( wk->bMove == FALSE );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	スコアボード 加算開始
 *
 *	@param	BOARD_WORK* wk
 *	@param	idx
 *	@param	add
 *
 *	@retval	none
 */
//-----------------------------------------------------------------------------
static void Board_StartAdd( BOARD_WORK* wk, u16 add )
{
	wk->Score = MATH_CLAMP( wk->Score + add, 0, BD_SCORE_MAX );
	wk->bMove = TRUE;
}


//-----------------------------------------------------------------------------
/**
 *	@brief	紙ふぶき 初期化
 *
 *	@param	PTC_EFFECT_WORK* wk
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void PtcEffect_Init( PTC_EFFECT_WORK* wk, CATS_SYS_PTR csp, CATS_RES_PTR crp )
{
	GF_ASSERT( wk );

	// オールクリア
	MI_CpuClear8( wk, sizeof( PTC_EFFECT_WORK ) );
	wk->speed_y_fx = FX32_CONST( 1.5 ) + ( FX32_CONST( gf_mtRand() % 5 ) >> 1 );
	wk->speed_x_fx = FX32_CONST( 0.1 ) + FX32_CONST( gf_mtRand() % 2 ) >>1;
	wk->pos_x_fx = FX32_CONST( gf_mtRand() % GX_LCD_SIZE_X );
	wk->turn_lim = 1 + ( gf_mtRand() % 5 );	///< ふれ幅ランダム
	wk->enable = TRUE;

	// CAP生成
	{
		TCATS_OBJECT_ADD_PARAM_S prm = {
			0, 0, 0,
			PTC_ANM_ID_0, 0, 0, NNS_G2D_VRAM_TYPE_2DSUB,
			{ CHR_ID_S_OPED, PAL_ID_S_OPED, CEL_ID_S_OPED, ANM_ID_S_OPED },
			1, 0,
		};
		prm.x = wk->pos_x_fx >> FX32_SHIFT;
		if( gf_mtRand() % 2 == 0 ){ prm.anm = PTC_ANM_ID_1; }

		wk->cap = CATS_ObjectAdd_S_SubDistance( csp, crp, &prm, CATS_DISTANCE );
		CATS_ObjectAutoAnimeSetCap( wk->cap, TRUE );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	紙ふぶき 主処理
 *
 *	@param	PTC_EFFECT_WORK* wk
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL PtcEffect_Main( PTC_EFFECT_WORK* wk )
{
	BOOL ret = FALSE;
	fx32 add_x;

	GF_ASSERT( wk );

	add_x = FX_Mul( Sin360R( wk->cnt * wk->turn_lim ), wk->speed_x_fx );

	wk->pos_x_fx += add_x;
	wk->pos_y_fx += wk->speed_y_fx;

	// OBJ移動 メイン画面表示時は回り込みを回避する
	CATS_ObjectPosSetCapFx32_SubSurface( wk->cap, wk->pos_x_fx, wk->pos_y_fx, CATS_DISTANCE );

	if( FX_Whole( wk->pos_y_fx ) > GX_LCD_SIZE_Y + 32 )
	{
		if( wk->disp_drop )
		{
			// 消去
			wk->enable = FALSE;
			CATS_ActorPointerDelete_S( wk->cap );
			wk->cap = NULL;
		}
		else
		{
			// 上下切替
			wk->disp_drop = TRUE;
			ret = TRUE;
		}
	}
	wk->cnt += gf_mtRand() % 2;

	return ret;
}

//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	PTC_EFFECT_WORK* wk
 *	@param	csp
 *	@param	crp
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void PtcEffect_DispDrop( PTC_EFFECT_WORK* wk, CATS_SYS_PTR csp, CATS_RES_PTR crp )
{
	TCATS_OBJECT_ADD_PARAM_S prm = {
		0, 0, 0,
		0, 0, 0, NNS_G2D_VRAM_TYPE_2DMAIN,
		{ CHR_ID_M_OPED, PAL_ID_M_OPED, CEL_ID_M_OPED, ANM_ID_M_OPED },
		0, 0,
	};

	wk->pos_y_fx = 0;

	prm.anm = CATS_ObjectAnimeSeqGetCap( wk->cap ) - PTC_ANM_ID_0;
	prm.x = FX_Whole( wk->pos_x_fx );
	prm.y = FX_Whole( wk->pos_y_fx );

	CATS_ActorPointerDelete_S( wk->cap );
	wk->cap = CATS_ObjectAdd_S_SubDistance( csp, crp, &prm, CATS_DISTANCE );
	CATS_ObjectAutoAnimeSetCap( wk->cap, TRUE );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	紙ふぶき管理 生成
 *
 *	@param	HEAPID HeapID
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static PTC_EFFECT_CNT_WORK* PtcEffectCnt_Create( HEAPID HeapID, CATS_SYS_PTR csp, CATS_RES_PTR crp )
{
	PTC_EFFECT_CNT_WORK* cnt;

	GF_ASSERT( csp );
	GF_ASSERT( crp );

	// Alloc
	cnt = sys_AllocMemory( HeapID, sizeof( PTC_EFFECT_CNT_WORK ) );
	MI_CpuClear8( cnt, sizeof( PTC_EFFECT_CNT_WORK ) );

	cnt->HeapID = HeapID;
	cnt->csp = csp;
	cnt->crp = crp;
	cnt->wait_frame = GetPtcAddWaitFrame();

	return cnt;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	紙ふぶき管理 消去
 *
 *	@param	PTC_EFFECT_CNT_WORK* wk
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void PtcEffectCnt_Delete( PTC_EFFECT_CNT_WORK* wk )
{
	int i;

	GF_ASSERT( wk );

	// 強制削除
	for( i=0; i<PTC_NUM; i++ )
	{
		if( wk->ptc[i].cap )
		{
			HOSAKA_PRINT("[%d]del cap=0x%x\n",i, wk->ptc[i].cap);
			CATS_ActorPointerDelete_S( wk->ptc[i].cap );
			wk->ptc[i].cap = NULL;
		}
	}
	sys_FreeMemoryEz( wk );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	紙ふぶき管理 メイン処理
 *
 *	@param	PTC_EFFECT_CNT_WORK* wk
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void PtcEffectCnt_Main( PTC_EFFECT_CNT_WORK* wk )
{
	int i;

	GF_ASSERT( wk );

	if( wk->b_auto )
	{
		if( wk->cnt++ > wk->wait_frame )
		{
			PtcEffectCnt_Add( wk, PTC_ADD_DEF + ( gf_mtRand() % PTC_ADD_RND_MAX ) );
			wk->wait_frame = GetPtcAddWaitFrame();
			wk->cnt = 0;
		}
	}

	for( i=0; i<PTC_NUM; i++ )
	{
		if( wk->ptc[i].enable ==TRUE )
		{
			if( PtcEffect_Main( &wk->ptc[i] ) )
			{
				// CAPを下画面に切り替え
				PtcEffect_DispDrop( &wk->ptc[i], wk->csp, wk->crp );
			}
		}
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	紙ふぶき管理 自動発生切替
 *
 *	@param	PTC_EFFECT_CNT_WORK* wk
 *	@param	b_auto
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void PtcEffectCnt_SetAutoAdd( PTC_EFFECT_CNT_WORK* wk, BOOL b_auto )
{
	wk->b_auto = b_auto;
	// パレットのっとり
	ArcUtil_PalSet( ARC_PKTHEV_OPED, NARC_pkthev_oped_obj_oped_nclr, PALTYPE_MAIN_OBJ, PTC_PAL_OFS*0x20, 0x20, wk->HeapID );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	紙ふぶき管理 紙ふぶき生成
 *
 *	@param	PTC_EFFECT_CNT_WORK* wk
 *	@param	u8 create_num
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void PtcEffectCnt_Add( PTC_EFFECT_CNT_WORK* wk, u8 create_num )
{
	int i;
	int cnt = 0;

	GF_ASSERT( wk );

	for( i=0; i<PTC_NUM; i++ )
	{
		if( wk->ptc[i].enable == FALSE )
		{
			PtcEffect_Init( &wk->ptc[i], wk->csp, wk->crp );

			if( ++cnt >= create_num )
			{
				break;
			}
		}
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	共通初期化処理
 *
 *	@param	work
 *	@param	*pParam
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static PTH_RC Common_InitFunc(PKTHLN_PTR work, void *pParam)
{
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);
	u8 seq = PTFrame_GetSubSeq(work);

	switch(seq){
	case 0:
		{
			int heap_id;
			sys_CreateHeap( HEAPID_POKETHLON, HEAPID_PT_OPED, OPED_HEAP_SIZE );
			heap_id = HEAPID_PT_OPED;

			Overlay_Load( FS_OVERLAY_ID(pkthln_common), OVERLAY_LOAD_NOT_SYNCHRONIZE );

			sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
			sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

			GF_Disp_GX_VisibleControlInit();
			GF_Disp_GXS_VisibleControlInit();
			GX_SetVisiblePlane( 0 );
			GXS_SetVisiblePlane( 0 );

			//VRAMバンク割り当て
			SetVramBank();

			//アプリケーションメモリー
			ptr = PTFrame_AllocEventWork(work, sizeof(OPENING_WORK));
			MI_CpuClear8( ptr, sizeof(OPENING_WORK));

			ptr->HeapID = heap_id;
			ptr->CrsID = PTFrame_GetCourseID(work);

#if 0
#ifdef PM_DEBUG
			// LかRを押してるとランダムでコース指定
			if( sys.cont & PAD_BUTTON_L )
			{
				ptr->CrsID = gf_mtRand() % 5;
			}
			else if( sys.cont & PAD_BUTTON_R )
			{
				ptr->CrsID = 5 + gf_mtRand() % 5;
			}
#endif
#endif

			//BGLアロケーション
			ptr->bgl = GF_BGL_BglIniAlloc( ptr->HeapID );

			//メッセージコントローラ
			ptr->MsgCnt = MSG_CNT_Create( ptr->HeapID );

			// CATS初期化
			CATS_Create( ptr );

			ptr->CmnResCntPtr = CmnRes_Init( ptr->HeapID, CMN_RES_SHADOW_BIT | CMN_RES_MARKER_BIT, NNS_G2D_VRAM_TYPE_2DMAIN );
		}

		//下画面をメインにする
		sys.disp3DSW = DISP_3D_TO_SUB;
		GF_Disp_DispSelect();

		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 1:
		// アクターの初期化
		{
			int i;
			MONS_INFO info[OPENING_EVENT_POKE_NUM];
			PCLACT_SET_PARAM param = {0};

			//ポケモンアクター
			ptr->PokeActCntPtr = PokeAct_Init( ptr->HeapID, OPENING_EVENT_POKE_NUM, POKE_PRIORITY,
									  ptr->CmnResCntPtr, CATS_GetClactSetPtr(ptr->crp) );

			for(i=0;i<OPENING_EVENT_POKE_NUM;i++)
			{
				const PKTHPOKE_PARAM* pp;

				PTFrame_SetMonsInfo(work, i/ENTRY_MAX, i%ENTRY_MAX, &info[i]);
				pp = PTFrame_GetPkthlnParam(work, i/ENTRY_MAX, i%ENTRY_MAX);
				param.ShadowPos[i] = PTFrame_GetPokeShdwPosType( pp );
			}

			param.Quick = 0;
			param.Trans = 0;
			param.BGPriority = POKE_PRIORITY;
			param.ResVramType = NNS_G2D_VRAM_TYPE_2DMAIN;
			param.DrawArea = NNS_G2D_VRAM_TYPE_2DMAIN;

			PokeAct_SetPokeActor( ptr->PokeActCntPtr, OPENING_EVENT_POKE_NUM,
								  info, &param, PCLACT_TCB_PRIORITY, 0 );
		}

		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 2:
		if( PokeAct_CheckActSetTask( ptr->PokeActCntPtr ) )
		{
			//CATSアクター リソースロード
			CATS_LoadRes( work );

			// アクター生成
			CATS_AddMapModel( ptr );
			CATS_AddScoreBoard( ptr );
			CATS_AddPokegra( ptr );
			CATS_AddMedal( ptr );

			// ボードコントローラー 生成
			ptr->wkBoardCnt = BoardCnt_Create( ptr->HeapID, ptr->cap );
			ptr->wkPtcCnt = PtcEffectCnt_Create( ptr->HeapID, ptr->csp, ptr->crp );

			// CATSのダミーCGX,PLTTにテクスチャ展開
			MANOBJ_Setup(work);

			//次のシーケンスへ
			PTFrame_IncSubSeq(work);
		}
		break;
	case 3:
		{
			int i;
			PTFrame_SetDefaultVBlankFunc(ptr->bgl);	// VBlankセット
			//描画を許可
			PTFrame_SetDraw(work, TRUE);
			//ポケセルアクター可視化
			for (i=0;i<OPENING_EVENT_POKE_NUM;i++){
				POKE_ACT_PTR poke_act_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);
				PokeAct_DispCnt(poke_act_ptr, TRUE);	//表示
				//ポケモン初期位置
				{
					int ofs_y, ofs_x;
					const MONS_INFO *info;
					PCLACT_PTR pclact_ptr = PokeAct_GetPclActPtr( poke_act_ptr );

					// アニメ再生タイミングをずらす
					{
						CLACT_WORK_PTR cl_act;
						NNSG2dAnimController* anim_ctrl;

						cl_act = PCLACT_GetClActWorkPtr( pclact_ptr );
						anim_ctrl = CLACT_GetAnimController( cl_act );

						NNS_G2dSetAnimCtrlCurrentTime( anim_ctrl, i*3*FX32_ONE );
					}

					//向きセット
					PokeAct_SetDir(poke_act_ptr, POKE_DIR_UP);

					//アクター位置セット
					ofs_y = -DRAW_OFS_Y;
					ofs_x = -DRAW_OFS_X;

					PokeAct_SetPosShadow(poke_act_ptr,
							ARRAY_BASE_X + 64*(i/3) + ofs_x,
							ARRAY_BASE_Y + 48*(i%3) + ofs_y);
				}
			}

			BgInit(ptr->bgl);
			SetGraphic(ptr->bgl, ptr->HeapID);

			// メッセージコントローラ 初期化
			MSG_CNT_Init( ptr->MsgCnt, ptr->bgl, GF_BGL_FRAME0_S, PTFrame_GetGameType( work ), PTFrame_GetSaveData( work ) );

			// 通信アイコンを呼び出し
			WirelessIconEasyPokethlon( NNS_G2D_VRAM_TYPE_2DSUB );

			//SUB OBJの表示
			GF_Disp_GXS_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );		// SUB DISP OBJ ON
			GF_Disp_GX_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );		// MAIN DISP OBJ ON

			//メインシーケンス初期化
			ptr->Seq = OP_SEQ_START;

			//初期化終了
			sys_PrintHeapFreeSize( ptr->HeapID );

			return PTH_RC_END;
		}
		break;
	default : GF_ASSERT(0);
	}
	return PTH_RC_LOOP;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	共通描画処理
 *
 *	@param	work
 *	@param	*pParam
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL Common_DrawFunc(PKTHLN_PTR work, void *pParam)
{
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);
	CATS_Draw( ptr->crp );
	return TRUE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	共通終了処理
 *
 *	@param	work
 *	@param	*pParam
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL Common_EndFunc(PKTHLN_PTR work, void *pParam)
{
	int i;
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);

	sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
	sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

	PtcEffectCnt_Delete( ptr->wkPtcCnt );
	BoardCnt_Delete( ptr->wkBoardCnt );
	MSG_CNT_Delete( ptr->MsgCnt );

	//BG削除
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME0_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME1_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME0_S );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME1_S );
	//BGL解放
	sys_FreeMemoryEz(ptr->bgl);

	//ポケアクターコントローラ解放
	PokeAct_Free(ptr->PokeActCntPtr);
	//共通リソースコントローラ解放
	CmnRes_Free(ptr->CmnResCntPtr);

	// ワイヤレスアイコン開放
	WirelessIconEasyEnd();

	//CATS開放
	CATS_Delete( ptr );

	//イベントワーク解放
	PTFrame_FreeEventWork(work);

	// 上下画面を元に戻しておく
	sys.disp3DSW = DISP_3D_TO_MAIN;
	GF_Disp_DispSelect();

	Overlay_UnloadID( FS_OVERLAY_ID(pkthln_common) );

	//ヒープ解放
	sys_DeleteHeap( HEAPID_PT_OPED );

	return TRUE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモン名をプリント
 *
 *	@param	work
 *	@param	TeamIdx
 *	@param	pokeIdx
 *	@param	regIdx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void PrintPokemonName(PKTHLN_PTR work, u8 TeamIdx, u8 pokeIdx, u32 regIdx)
{
	STRBUF* pBuf;
	POKETHLON_ENTRY_DATA* pEnt;
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);

	pEnt = PTFrame_GetEntryDataPtrByID( work, TeamIdx );
	pBuf = STRBUF_Create( MONS_NAME_SIZE+EOM_SIZE, ptr->HeapID );

	STRBUF_SetStringCode( pBuf, pEnt[ pokeIdx ].NickName );
	WORDSET_RegisterWord( MSG_CNT_GetWordSet(ptr->MsgCnt), regIdx, pBuf, PM_NEUTRAL, TRUE, NULL );

	STRBUF_Delete( pBuf );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	チーム名と得点をプリント
 *
 *	@param	ptr
 *	@param	WordSet
 *	@param	idx
 *	@param	num
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void PrintTeamScore(PKTHLN_PTR work, u8 TeamIdx, int num)
{
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr( work );
	WORDSET* WordSet = MSG_CNT_GetWordSet( ptr->MsgCnt );
	// トレーナー名レジスト
	WORDSET_RegisterPlayerName( WordSet, 0, PTFrame_GetMyStatus(work, TeamIdx) );
	// 値レジスト
	WORDSET_RegNum( WordSet, num, 3, 1 );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	チーム名とポケモン名をプリント
 *
 *	@param	work
 *	@param	TeamIdx
 *	@param	pokeIdx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void PrintTeamPokemon(PKTHLN_PTR work, u8 TeamIdx, u8 pokeIdx )
{
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr( work );
	WORDSET* WordSet = MSG_CNT_GetWordSet( ptr->MsgCnt );
	// トレーナー名レジスト
	WORDSET_RegisterPlayerName( WordSet, 0, PTFrame_GetMyStatus(work, TeamIdx) );
	PrintPokemonName( work, TeamIdx, pokeIdx, 1 );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ノーミスのポケモンの存在チェック
 *
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL CheckNoMissPokemonExist(PKTHLN_PTR work)
{
	GET_ED_RECIVE(work,data,parent);
	return ( MATH_CountPopulation(parent->NoMissPoke) );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	指定ポケモンがノーミスか
 *
 *	@param	work
 *	@param	TeamIdx
 *	@param	PokeIdx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL CheckNoMissPokemon(PKTHLN_PTR work, u8 TeamIdx, u8 PokeIdx)
{
	int idx = TeamIdx * ENTRY_MAX + PokeIdx;
	GET_ED_RECIVE(work,data,parent);

	GF_ASSERT( idx < ENTRY_MAX * TEAM_NUM );

	return ( parent->NoMissPoke & (1<<idx) );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	指定ポケモンがポイント王か
 *
 *	@param	work
 *	@param	TeamIdx
 *	@param	PokeIdx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL CheckPointKingPoke(PKTHLN_PTR work, u8 TeamIdx, u8 PokeIdx)
{
	int idx = TeamIdx * ENTRY_MAX + PokeIdx;
	GET_ED_RECIVE(work,data,parent);

	GF_ASSERT( idx < ENTRY_MAX * TEAM_NUM );

	return ( parent->KingPoke & (1<<idx) );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	指定ポケモンが努力賞を取っているか
 *
 *	@param	work
 *	@param	all_idx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL CheckEffortPrizePoke(PKTHLN_PTR work, u8 TeamIdx, u8 PokeIdx )
{
	int idx = TeamIdx * ENTRY_MAX + PokeIdx;
	GET_ED_RECIVE(work,data,parent);
	return ( parent->EffortPoke & (1<<idx) );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	次の紙ふぶきを生成するまでの時間を取得
 *
 *	@param	none
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u32 GetPtcAddWaitFrame(void)
{
	return PTC_ADD_FRAME_BASE + gf_mtRand() % PTC_ADD_FRAME_RND;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモンボーナス値を取得
 *
 *	@param	work
 *	@param	idx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u8 GetPokemonBonus(PKTHLN_PTR work, u8 idx )
{
	GET_ED_RECIVE(work,data,parent);
	return parent->PokeBonus[idx];
}

//-----------------------------------------------------------------------------
/**
 *	@brief	競技で獲得した得点を取得
 *
 *	@param	work
 *	@param	TeamIdx
 *	@param	EvtCodeIdx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static int GetEventScore(PKTHLN_PTR work, u8 TeamIdx, u8 EvtCodeIdx )
{
	u8 evtIdx;
	RSLT_PTR rslt;

	evtIdx = PTFrame_GetEventCodeByIdx( work, EvtCodeIdx );
	rslt = PTFrame_GetResultPtr( work );

	return RSLT_GetEvtScore( rslt, evtIdx, TeamIdx );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ノーミスポイントを取得
 *
 *	@param	ptr
 */
//-----------------------------------------------------------------------------
static u32 GetNoMissScore(OPENING_PTR ptr)
{
	return SCORE_NO_MISS;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	キングポイントを取得
 *
 *	@param
 */
//-----------------------------------------------------------------------------
static u32 GetKingPoint(OPENING_PTR ptr)
{
	return SCORE_KING;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	努力点を取得
 *
 *	@param	ptr
 */
//-----------------------------------------------------------------------------
static u32 GetEffortPoint(OPENING_PTR ptr)
{
	return SCORE_EFFORT;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ノーミスボーナスを取ったポケモン数
 *
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u8 GetNomissCount(PKTHLN_PTR work)
{
	GET_ED_RECIVE(work, data, parent);
	return MATH_CountPopulation( parent->NoMissPoke );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポイント王を取ったポケモン数
 *
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u8 GetKingPointCount(PKTHLN_PTR work)
{
	GET_ED_RECIVE(work, data, parent);
	return MATH_CountPopulation( parent->KingPoke );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	努力賞を取ったポケモン数
 *
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u8 GetEffortPrizeCount(PKTHLN_PTR work)
{
	GET_ED_RECIVE(work, data, parent);
	return MATH_CountPopulation( parent->EffortPoke );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	同点時の優先度を取得
 *
 *	@param	work
 *	@param	outArray[]
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void GetDrawWinPoint(PKTHLN_PTR work, u8 outArray[] )
{
	int i;
	GET_ED_RECIVE(work,data,parent);

	for( i=0; i<TEAM_NUM; i++ )
	{
		outArray[i] = parent->DrawWinPoint[i];
	}
}

#ifdef PM_DEBUG
//-----------------------------------------------------------------------------
/**
 *	@brief	ダミーデータのセット
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void SetDummyData( PKTHLN_PTR work )
{
	int i,p,t;
	PKTHLN_SVSET_DATA* svset = PTFrame_GetSvSetDataPtr(work);

	for(t=0;t<TEAM_NUM;t++)
	{
		for(p=0;p<ENTRY_MAX;p++)
		{
			svset->PokeRslt[t][p].Attack = gf_mtRand() % 20;
			svset->PokeRslt[t][p].Dash = gf_mtRand() % 40;
			svset->PokeRslt[t][p].Get = gf_mtRand() % 80;
			svset->PokeRslt[t][p].Jump = gf_mtRand() % 200;
			svset->PokeRslt[t][p].Fall = gf_mtRand() % 2;
			svset->PokeRslt[t][p].Fail = gf_mtRand() % 2;
			svset->PokeRslt[t][p].OwnGoal = gf_mtRand() % 2;
		}

		// 各チームの獲得点
		for(i=0; i<COMM_EVT_MAX; i++ )
		{
			svset->EvtScore[t][i] = gf_mtRand() % 200;
			svset->EvtRecord[t][i] = gf_mtRand() % 100;
		}
	}

}
#endif

//-----------------------------------------------------------------------------
/**
 *	@brief	通信データからあおり文のメッセージIDを取得
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u32 OP_GetBlastMsgIdx( PKTHLN_PTR work, u8 team_idx )
{
	GET_OP_RECIVE(work,data,parent);
	return parent->TeamData[ team_idx ].BlastMsgIdx;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	通信データからあおり文に表示する数値を取得
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u32 OP_GetBlastPoint( PKTHLN_PTR work, u8 team_idx )
{
	GET_OP_RECIVE(work,data,parent);
	return parent->TeamData[ team_idx ].BlastPoint;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	通信データからファン段階を取得
 *
 *	@param	PKTHLN_PTR work
 *	@param	team_idx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u32 OP_GetFunLevel( PKTHLN_PTR work, u8 team_idx )
{
	GET_OP_RECIVE(work,data,parent);
	return parent->TeamData[ team_idx ].FunLevelBit;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	OP:通信用のデータを生成（親用）
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void OP_SendShareData( PKTHLN_PTR work )
{
	int i;
	COMM_EVENT_COMMON_DATA* data;
	OPENING_COMM_PTR parent;

	data = PTFrame_GetEvtComCmnData( work );
	parent = PKTHLN_CommPack_GetData( &data->SendShareData );

	// -- データ取得
	if( PTFrame_GetGameType(work) == PKTHLN_GAME_ALONE )
	{
		for( i=0; i<TEAM_NUM; i++ )
		{
			if( i == PTFrameGetCurrentID(work) )
			{
				// my data
				SetCommTeamDataAlone( &parent->TeamData[ i ], work );
			}
			else
			{
				// NPC
				SetCommTeamDataNpc( &parent->TeamData[ i ], work, i );
			}
		}
	}
	else
	{
		// 通信
		for( i=0; i<TEAM_NUM; i++ )
		{
			if( PTFrame_GetPlayerNum( work ) > i )
			{
				// Net Player Data
				SetCommTeamDataComm( &parent->TeamData[ i ], work, i );
			}
			else
			{
				// NPC
				SetCommTeamDataNpc( &parent->TeamData[ i ], work, i );
			}
		}
	}

#ifdef PM_DEBUG
	HOSAKA_PRINT( "----- 開会式 紹介データ -----\n" );
	for( i=0; i<TEAM_NUM; i++ )
	{
		HOSAKA_PRINT( "--[%d]--\n", i );
		HOSAKA_PRINT( "msg_idx:%d\n", parent->TeamData[i].BlastMsgIdx );
		HOSAKA_PRINT( "point:%d\n", parent->TeamData[i].BlastPoint );
		HOSAKA_PRINT( "fan level:%d\n", parent->TeamData[i].FunLevelBit );
	}
#endif
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポケモンボーナスを計算
 *
 *	@param	PKTHLN_PTR work
 *	@param	u8 netID
 *
 *	@retval	計算結果
 */
//-----------------------------------------------------------------------------
static u32 ED_CalcPokeBonus( PKTHLN_PTR work, u8 netID )
{
	enum{ DEF_BONUS = 75, };

	int i;
	ARCHANDLE* handle;
	POKETHLON_ENTRY_DATA* pEntryData;

	int bonus = DEF_BONUS;

	// アーカイブハンドルを開く
	handle = ArchiveDataHandleOpen( ARC_PKTHPOKE_PARAM, PTFrame_GetHeapID(work) );
	// 登録情報を取得
	pEntryData = PTFrame_GetEntryDataPtrByID( work, netID );

	for(i=0; i<ENTRY_MAX; i++)
	{
		int monsno;
		int form;
		int idx;
		PKTHPOKE_PARAM param;

		monsno = pEntryData[i].MonsNo;
		form = pEntryData[i].Form;

		// アーカイブインデックス取得
		idx = PTFrame_GetPokeParamArcIdx(monsno, form);
		ArchiveDataLoadByHandle( handle, idx, &param );

		bonus -= param.Power+1;
		bonus -= param.Speed+1;
		bonus -= param.Jump+1;
		bonus -= param.Stamina+1;
		bonus -= param.Technique+1;
	}

	bonus = MATH_CLAMP( bonus, 0, DEF_BONUS );

	// ハンドルクローズ
	ArchiveDataHandleClose( handle );

	return bonus;
}


//-----------------------------------------------------------------------------
/**
 *	@brief	努力賞を抽選
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static int ED_CalcEffort( PKTHLN_PTR work )
{
	int i,t,p;
	BOOL bCheck = FALSE;
	int EffortType = gf_mtRand() % EFFORT_MAX;

	for( i=0; i<EFFORT_MAX; i++ )
	{
		// 0以上の値を持ったポケモンがいるかチェック

		// チームチェック
		for( t=0; t<TEAM_NUM; t++ )
		{
			// ポケチェック
			for( p=0; p<ENTRY_MAX; p++ )
			{
				if( GetEffortData( work, EffortType, t, p ) > 0 )
				{
					bCheck = TRUE;
					break;
				}
			}

			if( bCheck )
			{
				break;
			}
		}

		if( bCheck )
		{
			break;
		}
		else
		{
			// 再抽選
			EffortType = (EffortType+1) % EFFORT_MAX;
		}
	}

	// 最後まで回って最高点が0だった場合は努力賞なし
	if( bCheck == FALSE )
	{
		EffortType = EFFORT_NULL;
	}

	return EffortType;
}


//-----------------------------------------------------------------------------
/**
 *	@brief	ED:通信用のデータを生成（親用）
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void ED_SendShareData( PKTHLN_PTR work )
{
	int i;
	COMM_EVENT_COMMON_DATA* data;
	ENDING_COMM_PTR parent;
	PKTHLN_SVSET_DATA* svset = PTFrame_GetSvSetDataPtr(work);

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->SendShareData);

	// 初期化
	parent->NoMissPoke = 0;
	parent->EffortPoke = 0;
	parent->KingPoke = 0;

#ifdef PM_DEBUG
// #ifdef DEBUG_ONLY_FOR_genya_hosaka
	// DEBUGでダミーデータを設定
	if( PTFrame_GetGameType(work) == PKTHLN_GAME_ALONE && (sys.cont & PAD_BUTTON_DEBUG) )
	{
		HOSAKA_PRINT("ダミーデータをセット\n");
		SetDummyData(work);
	}
// #endif
#endif

	// -- ポケボーナス --
	for( i=0; i<TEAM_NUM; i++ )
	{
		parent->PokeBonus[i] = ED_CalcPokeBonus( work, i );
	}

	// -- 努力賞 --
	// 努力賞の種類を決定
	parent->EffortType = ED_CalcEffort(work);

#ifdef PM_DEBUG
	if( DebugPkthlnWk.EffortTypeFlg )
	{
		parent->EffortType = DebugPkthlnWk.EffortType;
	}
#endif

	{
		int t,p;
		int EffortPoint = 0;
		int KingPoint = 0;
		int EffortType;

		EffortType = parent->EffortType;

		// 一番ポイント獲得回数が多いポケモン、努力点が高いポケモンを調べる
		for( t=0; t<TEAM_NUM; t++ )
		{
			for( p=0; p<ENTRY_MAX; p++ )
			{
				// 努力点最高更新
				if( EffortType != EFFORT_NULL )
				{
					int efdat = GetEffortData( work, EffortType, t, p );
					if( EffortPoint < efdat )
					{
						EffortPoint = efdat;
					}
				}

				// ポイント王値更新
				if( KingPoint < svset->PokeRslt[t][p].Get )
				{
					KingPoint = svset->PokeRslt[t][p].Get;
				}
			}
		}

#ifdef PM_DEBUG
		OS_TPrintf("EffortType:%d\n", parent->EffortType);
		OS_TPrintf("EffortPoint=%d KingPoint=%d \n", EffortPoint, KingPoint );
#endif

		// 各ポケモンのフラグ立て
		for( t=0; t<TEAM_NUM; t++ )
		{
			for( p=0; p<ENTRY_MAX; p++ )
			{
				u8 shift = t * ENTRY_MAX + p;

				OS_TPrintf("[%d,%d] Attack:%d Change:%d Dash:%d Fail:%d Fall:%d, Get:%d Jump:%d, OwnGoal:%d \n", t, p,
						svset->PokeRslt[t][p].Attack,
						svset->PokeRslt[t][p].Change,
						svset->PokeRslt[t][p].Dash,
						svset->PokeRslt[t][p].Fail,
						svset->PokeRslt[t][p].Fall,
						svset->PokeRslt[t][p].Get,
						svset->PokeRslt[t][p].Jump,
						svset->PokeRslt[t][p].OwnGoal );

				// ノーミスボーナス判定
				if( svset->PokeRslt[t][p].Fail == 0 &&
					svset->PokeRslt[t][p].Fall == 0 &&
					svset->PokeRslt[t][p].OwnGoal == 0 )
				{
					parent->NoMissPoke += 1 << shift;
				}

				// ポイント王判定
				if( KingPoint == svset->PokeRslt[t][p].Get )
				{
					parent->KingPoke += 1 << shift;
				}

				// 努力賞判定
				if( EffortType != EFFORT_NULL )
				{
					int efdat = GetEffortData( work, EffortType, t, p );


					GF_ASSERT( efdat <= EffortPoint );

					if( EffortPoint == efdat )
					{
						HOSAKA_PRINT("[%d,%d] Get Effort! Point=%d \n", t, p, efdat );
						parent->EffortPoke += 1 << shift;
					}
				}
			}
		}

		// 最高点を保持
		parent->EffortPoint = EffortPoint;
	}

	// -- 同点時の勝利優先度 --
	{
		int win_idx = gf_mtRand() % ENTRY_MEMBER_NUM_MAX;

		for( i=0; i<ENTRY_MEMBER_NUM_MAX; i++ )
		{
			parent->DrawWinPoint[ win_idx ] = i;
			win_idx = (win_idx+1) % ENTRY_MEMBER_NUM_MAX;
		}
	}

#ifdef PM_DEBUG
	OS_TPrintf( "DrawWinPoint{%d, %d, %d, %d} \n",
					parent->DrawWinPoint[0], parent->DrawWinPoint[1],
					parent->DrawWinPoint[2], parent->DrawWinPoint[3] );

	OS_TPrintf("NoMissPoke:%d \n", MATH_CountPopulation(parent->NoMissPoke) );
	OS_TPrintf("KingPoke:%d \n", MATH_CountPopulation( parent->KingPoke ) );
	OS_TPrintf("EffortPoke:%d \n", MATH_CountPopulation( parent->EffortPoke ) );
	OS_TPrintf("NoMissPokeCnt:0x%x \n",	parent->NoMissPoke );
	OS_TPrintf("KingPokeCnt:0x%x \n", parent->KingPoke );
	OS_TPrintf("EffortPointCnt:0x%x \n", parent->EffortPoke );
#endif
}

//-----------------------------------------------------------------------------
/**
 *	@brief	メダルのIDXを取得
 *
 *	@param	u8 crs_idx
 *	@param	u8 mdl_idx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u8 GetMedalIdx( u8 crs_idx, u8 mdl_idx )
{
	switch( crs_idx )
	{
	case CRS_ID_MAS:
		return 0;	// ダミー値
	case 5:
		return ( mdl_idx ? CRS_ID_JMP : CRS_ID_SPD );
	case 6:
		return ( mdl_idx ? CRS_ID_TEQ : CRS_ID_JMP );
	case 7:
		return ( mdl_idx ? CRS_ID_POW : CRS_ID_TEQ );
	case 8:
		return ( mdl_idx ? CRS_ID_STA : CRS_ID_POW );
	case 9:
		return ( mdl_idx ? CRS_ID_SPD : CRS_ID_STA );
	default:
		return crs_idx;
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	努力賞の種類を取得
 *
 *	@param	PKTHLN_PTR work ポケスロンワーク
 *
 *	@retval	努力賞の種類
 */
//-----------------------------------------------------------------------------
static u8 GetEffortType( PKTHLN_PTR work )
{
	GET_ED_RECIVE(work, data, parent);

	return parent->EffortType;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	努力賞の種類に応じた値を PKTHLN_SVSET_DATA から取得
 *
 *	@param	PKTHLN_PTR work	ポケスロンワーク
 *	@param	EffortType	努力賞の種類
 *	@param	TeamIdx		チームIDX
 *	@param	PokeIdx		ポケモンIDX
 *
 *	@retval	取得した値
 */
//-----------------------------------------------------------------------------
static u32 GetEffortData( PKTHLN_PTR work, u8 EffortType, u8 TeamIdx, u8 PokeIdx )
{
	PKTHLN_SVSET_DATA* svset = PTFrame_GetSvSetDataPtr(work);

	GF_ASSERT( TeamIdx < TEAM_NUM );
	GF_ASSERT( PokeIdx < ENTRY_MAX );

	switch( EffortType )
	{
	case EFFORT_JUMP :
		return svset->PokeRslt[TeamIdx][PokeIdx].Jump;
	case EFFORT_ATTACK :
		return svset->PokeRslt[TeamIdx][PokeIdx].Attack;
	case EFFORT_MISS :
		return svset->PokeRslt[TeamIdx][PokeIdx].Fail;
	case EFFORT_DASH :
		return svset->PokeRslt[TeamIdx][PokeIdx].Dash;
	default : GF_ASSERT(0);
	}

	GF_ASSERT(0);
	return 0; // dummy
}

//-----------------------------------------------------------------------------
/**
 *	@brief	PokeCntをループさせつつTeamCntも加算
 *
 *	@param	ptr
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL AddPokeCnt(OPENING_PTR ptr)
{
	ptr->PokeCnt++;

	if( ptr->PokeCnt >= ENTRY_MAX ){ ptr->PokeCnt = 0; ptr->TeamCnt++; }

	return ( ptr->TeamCnt == TEAM_NUM );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ボーナススコア加点 マクロ関数
 *
 *	@param	work	ポケスロン用ワーク
 *	@param	(*func)(PKTHLN_PTR,u8,u8)	チームIDとポケIDから存在チェックをする関数へのポインタ
 *	@pram	score 加点するスコア
 *
 *	@note	内部でOPENING_PTRのTeamCntとPokeCntを変更することによって頭だしする。
 *			使用前にTeamCntとPokeCntの初期化が必要。
 *
 *	@retval	TRUE : TeamCntが溢れた。次の処理へ進めるべき。
 */
//-----------------------------------------------------------------------------
static BOOL SearchAddBonus( PKTHLN_PTR work, BOOL (*func)(PKTHLN_PTR,u8,u8), u32 score )
{
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);

	// 頭だし
	while(1)
	{
		if( func( work, ptr->TeamCnt, ptr->PokeCnt ) )
		{
			break;
		}
		else
		{
			if( AddPokeCnt(ptr) ){ break; }
		}
	}

	// 加点処理
	if( ptr->TeamCnt < TEAM_NUM )
	{
		int TotalID = ptr->TeamCnt * ENTRY_MAX + ptr->PokeCnt;

		ptr->BonusCount[ ptr->TeamCnt ]++; ///< ボーナス回数加算
		ptr->Cnt++;	///<取得数カウンタを加算

		// 描画
		PrintTeamPokemon( work, ptr->TeamCnt, ptr->PokeCnt );
		BoardCnt_StartAdd( ptr->wkBoardCnt, ptr->TeamCnt, score );
		SetAnimeTask( ptr, TotalID );

		// 鳴き声
		{
			POKE_ACT_PTR poke_ptr =	PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, TotalID );
			PCLACT_PTR pcl_ptr = PokeAct_GetPclActPtr(poke_ptr);
			const MONS_INFO* info = PCLACT_GetMonsInfo(pcl_ptr);

			// ペラップはデフォルト
			Snd_PerapVoiceDefaultFlagSet(TRUE);
			Snd_PMVoicePlay( info->MonsNo, info->Form );
		}

		HOSAKA_PRINT("teamidx:%d pokeidx:%d \n", ptr->TeamCnt, ptr->PokeCnt);

		// 次のポケモンを参照
		AddPokeCnt(ptr);

		return TRUE;
	}

	// TeamCnt が溢れた
	return FALSE;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	閉会式の結果をメインフレームに返す
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void ED_SetSvSetData( PKTHLN_PTR work, BOARD_CNT_WORK* wk )
{
	int CurrenID = PTFrameGetCurrentID(work);
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);
	PKTHLN_SVSET_DATA* svset = PTFrame_GetSvSetDataPtr(work);

	// 自分が優勝していた
	if( ptr->Grade[0].NetID == CurrenID )
	{
		svset->CrsWin = 1;
	}

	// 最下位チームを判定、フラグ立て
	{
		int i;
		int tail_score = 999;

		// 最低点を取得
		for(i=0; i<TEAM_NUM; i++){
			int new_score = BoardCnt_GetScore( wk, i );
			if (tail_score >= new_score ){
				tail_score = new_score;
			}
		}

		// 自分が最低点ならフラグを立てる
		{
			int my_score = BoardCnt_GetScore( wk, CurrenID );

			if( my_score == tail_score )
			{
				svset->CrsLose = 1;
			}
		}
	}

	// ボーナス取得回数を設定
	svset->BonusNum = ptr->BonusCount[ CurrenID ];
	svset->RsltScore = BoardCnt_GetScore( ptr->wkBoardCnt, CurrenID );

	// 最終順位
	{
		int grade;

		grade = Grade_GetGrade( ptr->Grade, CurrenID );
		GF_ASSERT( grade != -1 );

		svset->Rank = grade;
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	数字を登録するマクロ関数
 *
 *	@param	WORDSET* WordSet
 *	@param	num
 *	@param	figre
 *	@param	bufID
 *
 *	@retval	none
 */
//-----------------------------------------------------------------------------
static void WORDSET_RegNum( WORDSET* WordSet, int num, int figre, int bufID )
{
	WORDSET_RegisterNumber( WordSet, bufID, num, figre, NUMBER_DISPTYPE_LEFT, NUMBER_CODETYPE_DEFAULT );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ファン数をファン段階に変換する
 *
 *	@param	int FunNum
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static int GetFunLevel( int FunNum )
{
	enum
	{
		TBL_NUM = FUN_LEVEL_NUM - 1,
	};

	static const fun_level_tbl[ TBL_NUM ] =
	{
		11, 26, 51, 101, 201, 501, 1001, 2001, 5001, 10001, 20001, 50001,
	};

	int i = 0;

	for( i=0; i<TBL_NUM; i++ )
	{
		if( fun_level_tbl[i] > FunNum )
		{
			return i;
		}
	}
	return i;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	チームデータテーブルのIDXからあおりメッセージのIDXを取得
 *
 *	@param	u32 dat_idx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u32 GetBlastMessageIndexHeader( u32 dat_idx )
{
	return BLAST_MSG_HEADER + (BLAST_MSG_PATTERN * dat_idx);
}


//-----------------------------------------------------------------------------
/**
 *	@brief
 *
 *	@param	u32* outData
 *	@param	PKTH_RNK_DATA* p_rnk
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void SetTeamDataRank( u32* outData ,const PKTH_RNK_DATA* p_rnk )
{
	int i;
	int TotalEvtWinNum = 0;

	// 合計点を計算
	for( i=0; i<PKTHLN_EVT_MAX; i++ )
	{
		TotalEvtWinNum += p_rnk->EvtWinNum[i];
	}

	// 実データ取得
	outData[0]	= p_rnk->AlonePlay;
	outData[1]	= p_rnk->AloneWin;
	outData[2]	= p_rnk->AloneLose;
	outData[3]	= TotalEvtWinNum;
	outData[4]	= p_rnk->EvtLoseNum;
	outData[5]	= p_rnk->BonusNum;
	outData[6]	= p_rnk->TouchNum;
	outData[7]	= p_rnk->PokeFail;
	outData[8]	= p_rnk->PokeJump;
	outData[9]	= p_rnk->PointGet;
	outData[10]	= p_rnk->PokeAttack;
	outData[11]	= p_rnk->PokeFall;
	outData[12]	= p_rnk->PokeDash;
	outData[13]	= p_rnk->PokeChange;
	outData[14]	= p_rnk->CommPlay;
	outData[15]	= p_rnk->CommWin;
	outData[16]	= p_rnk->CommLose;

	for( i=0; i<PKTHLN_EVT_MAX; i++ )
	{
		outData[ 17 + i ] = p_rnk->EvtWinNum[i];
	}

	outData[27]	= p_rnk->OwnGoal;
	outData[28]	= p_rnk->FunNum;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	生のデータテーブルをポイント換算
 *
 *	@param	u8* outPoint
 *	@param	u32* srcData
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void SetTeamDataPoint( u8* outPoint, const u32* srcData )
{
	static const div_tbl[ BLAST_DAT_MAX ] = {
		8, // プレイ回数
		6, // シングルコース 一位
		3, // シングルコース ビリ
		15, // 競技 一位合計
		6, // 競技 ビリ合計
		18, // ボーナス獲得回数
		3000, // タッチ
		240, // 失敗
		360, // ジャンプ
		960, // ポイント獲得
		480, // アタック
		12, // 落ちた数
		900, // ダッシュ
		36, // 交代回数
		6, // 通信数
		3, // 通信 一位合計
		3, // 通信 ビリ合計
		2,2,2,2,2,2,2,2,2,2, // 各競技
		9, // 自殺点
		120, // ファン数
	};

	int i;

	for( i=0; i<BLAST_DAT_MAX; i++ )
	{
		GF_ASSERT( div_tbl[i] );

		// 規定ポイントをランダム値加算
		outPoint[i] = gf_mtRand() % 3;

		if( srcData[i] ){ outPoint[i] += ( srcData[i] / div_tbl[i] ); }

		HOSAKA_PRINT( "[%d] out point : %d srcData : %d \n", i,  outPoint[i], srcData[i] );
	}
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ポイントテーブルの最大値の中からIDXを抽選
 *
 *	@param	const u8* srcData
 *	@param	outPattern
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static u32 SelectTeamDataIdxFromPoint( const u8* srcPoint, u8* outPattern )
{
	int i;
	u8 max_idx_tbl[ BLAST_DAT_MAX ] = {0};
	u32 max = 0;					///< ポイントの最大値
	u32 max_cnt = 0;
	u32 select_idx = 0;

	// ポイント最大値
	for( i=0; i<BLAST_DAT_MAX; i++ )
	{
		if( max < srcPoint[i] )
		{
			max = srcPoint[i];
		}
	}

	// 最大値のIDX保持
	for( i=0; i<BLAST_DAT_MAX; i++ )
	{
		if( srcPoint[i] == max )
		{
			max_idx_tbl[ max_cnt ] = i;
			max_cnt++;
		}
	}

	// ポイント範囲からメッセージパターンを算出
	{
		static const range_tbl[] = { 11,6,3,0 };

		for( i=0; i<4; i++ )
		{
			if( max >= range_tbl[i] ){ *outPattern = 3-i; break; }
		}
	}


	// IDXを抽選
	select_idx = gf_mtRand() % max_cnt;

	HOSAKA_PRINT("max:%d max_cnt:%d select_idx:%d ",max, max_cnt, select_idx);
	HOSAKA_PRINT("max_idx_tbl[ select_idx ]:%d, outPattern:%d \n", max_idx_tbl[select_idx], *outPattern );

	return max_idx_tbl[ select_idx ];
}

//-----------------------------------------------------------------------------
/**
 *	@brief	チームデータ 自分のセーブデータから値をセット
 *
 *	@param	OP_COMM_TEAM_DATA* outData
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void SetCommTeamDataAlone( OP_COMM_TEAM_DATA* outData, PKTHLN_PTR work )
{
	SAVEDATA* p_sv;
	PKTHLN_SV_DATA_PTR p_pksv;
	const PKTH_RNK_DATA* p_rnk;
	u32 dat[ BLAST_DAT_MAX ] = {0};
	u8 point[ BLAST_DAT_MAX ] = {0};
	u8 dat_idx;
	u8 ptn_idx;

	HOSAKA_PRINT("===============================\n");
	HOSAKA_PRINT("チームデータ計算\n");

	p_sv = PTFrame_GetSaveData( work );
	p_pksv = PkthlnSv_GetSaveData( p_sv );
	p_rnk = PkthlnSv_GetRnkData( p_pksv );

	// ランクデータを展開
	SetTeamDataRank( dat, p_rnk );
	// ポイント換算
	SetTeamDataPoint( point, dat );
	// IDX算出
	dat_idx = SelectTeamDataIdxFromPoint( point, &ptn_idx );

	// 出力
	outData->BlastMsgIdx = GetBlastMessageIndexHeader( dat_idx ) + ptn_idx;
	outData->BlastPoint = dat[ dat_idx ];
	outData->FunLevelBit = GetFunLevel( p_rnk->FunNum );

	HOSAKA_PRINT("===============================\n");
}

//-----------------------------------------------------------------------------
/**
 *	@brief	チームデータ 通信時のワークから値をセット
 *
 *	@param	OP_COMM_TEAM_DATA* outData
 *	@param	work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void SetCommTeamDataComm( OP_COMM_TEAM_DATA* outData, PKTHLN_PTR work, u8 team_idx )
{
	const PKTH_RNK_DATA* p_rnk;
	u32 dat[ BLAST_DAT_MAX ] = {0};
	u8 point[ BLAST_DAT_MAX ] = {0};
	u8 dat_idx;
	u8 ptn_idx;

	p_rnk = PTFrame_GetRankDataPtr( work, team_idx );

	// ランクデータを展開
	SetTeamDataRank( dat, p_rnk );
	// ポイント換算
	SetTeamDataPoint( point, dat );
	// IDX算出
	dat_idx = SelectTeamDataIdxFromPoint( point, &ptn_idx );

	// 出力
	outData->BlastMsgIdx = GetBlastMessageIndexHeader( dat_idx ) + ptn_idx;
	outData->BlastPoint = dat[ dat_idx ];
	outData->FunLevelBit = GetFunLevel( p_rnk->FunNum );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	チームデータ NPCデータをセット
 *
 *	@param	OP_COMM_TEAM_DATA* outData
 *	@param	work
 *	@param	team_idx
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void SetCommTeamDataNpc( OP_COMM_TEAM_DATA* outData, PKTHLN_PTR work, u8 team_idx )
{
	int i;
	int FunNum = 0;
	COMMON_PLAYER_DATA* cmn_data = PTFrame_GetCmnPlayerDataPtrByID(work, team_idx);

	HOSAKA_PRINT(" *** NPC SET ***");
	// ポケ値を取得
	for( i=0; i<ENTRY_MAX; i++ )
	{
		const POKE_SPEC* spec = PTFrame_GetPokeSpec( work, team_idx, i );
		FunNum += (spec->Jump + spec->Power + spec->Speed + spec->Stamina + spec->Technique) + 5;
		HOSAKA_PRINT("[%d, %d, %d, %d, %d]\n", spec->Jump, spec->Power, spec->Speed, spec->Stamina, spec->Technique );
	}

	HOSAKA_PRINT("NPC[%d] TotalFun=%d ", team_idx, FunNum);

	FunNum = FunNum / 3 - 8;
	FunNum = MATH_CLAMP( FunNum, 0, FUN_LEVEL_NUM-1 ); // 上限clamp

	outData->BlastMsgIdx = PTFrame_GetNpcMsgIdx( work, cmn_data->PersonCode );
	outData->BlastPoint = 0;
	outData->FunLevelBit = FunNum;

	HOSAKA_PRINT("FunLevel = %d \n", FunNum);
}

//-----------------------------------------------------------------------------
/**
 *	@brief	順位を取得
 *
 *	@param	GRADE_DATA* pData
 *	@param	NetID
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static int Grade_GetGrade( GRADE_DATA* pData, u8 NetID )
{
	int i;

	for( i=0; i<TEAM_NUM; i++ )
	{
		if(	pData[i].NetID == NetID )
		{
			return pData[i].Grade;
		}
	}

	return -1;
}

//-----------------------------------------------------------------------------
/**
 *	@brief	同点時のソート
 *
 *	@param	GRADE_DATA* pData
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static void Grade_SortDraw( GRADE_DATA* pData )
{
	int i, j;
	int TopDrawWinPoint = 0;
	int TopID;

	HOSAKA_PRINT( "Grade_SortDraw PreData \n" );

	for( i=0; i<TEAM_NUM; i++ )
	{
		HOSAKA_PRINT("NetID:%d Grade:%d Score:%d\n",
			pData[i].NetID,
			pData[i].Grade,
			pData[i].Score );
	}

	for( i=0; i<TEAM_NUM; i++ )
	{
		// 一位
		if(	pData[i].Grade == 0 )
		{
			pData[i].Grade++; // 全員順位を下げる
			// 一位の中で一番DrawWinPointが高いIDを算出
			if( pData[i].DrawWinPoint > TopDrawWinPoint )
			{
				TopDrawWinPoint = pData[i].DrawWinPoint;
				TopID = i;
			}
		}
	}

	HOSAKA_PRINT("TopID:%d TopNetID:%d \n", TopID, pData[TopID].NetID );

	// 一位に選ばれた者は順位を上げる
	pData[TopID].Grade--;
	// 一時的に加点
	pData[TopID].Score += 1;

	// ソート
	MATH_QSort( (void*)pData, TEAM_NUM, sizeof(GRADE_DATA), GradeSortByScore, NULL );

	// TOPのスコアを元に戻す
	pData[0].Score -= 1;

	HOSAKA_PRINT( "Grade_SortDraw \n" );

	for( i=0; i<TEAM_NUM; i++ )
	{
		HOSAKA_PRINT("NetID:%d Grade:%d Score:%d\n",
			pData[i].NetID,
			pData[i].Grade,
			pData[i].Score );
	}
}


//-----------------------------------------------------------------------------
/**
 *	@brief	OPENING 通信処理
 *
 *	@param	PKTHLN_PTR work

 *	@retval TRUE:同期中（メッセージウェイトさせるべき）
 *
 *	@note	シーケンサが巻き戻ることも考慮している
 */
//-----------------------------------------------------------------------------
static BOOL OP_CommMain( PKTHLN_PTR work )
{
	int i;
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);
	COMM_EVENT_COMMON_DATA* data = PTFrame_GetEvtComCmnData(work);
	OPENING_COMM_PTR parent = PKTHLN_CommPack_GetData( &data->SendShareData );
	OPENING_COMM_PTR parent_rec = PKTHLN_CommPack_GetData( &data->ReciveShareData );

	u8 MyNetID = PTFrameGetCurrentID(work);
	u8 LocalMsgSeq = ptr->MsgSeq;

	BOOL bDelay = FALSE;

	// 親処理
	if( MyNetID == COMM_PARENT_ID )
	{
		BOOL bEnd = TRUE;

		// 送信メッセージシーケンス セット
		parent->MsgSeq = LocalMsgSeq;

		// 親の子機データは直接レシーバにセット
		{
			OPED_COMM_CHILD_PTR child;
			OPED_COMM_CHILD_PTR child_rec;

			child_rec = PKTHLN_CommPack_GetData(&data->ReciveData[0]);
			child = PKTHLN_CommPack_GetData(&data->SendData);
			(*child_rec) = (*child);
		}

		// レシーバー集計
		// (AIはメッセージを待たないので飛ばす)
		for( i=0; i<PTFrame_GetPlayerNum(work); i++ )
		{
			OPED_COMM_CHILD_PTR child_rec;

			child_rec = PKTHLN_CommPack_GetData(&data->ReciveData[i]);

			//------------------------------------------------------
			// 子のメッセージシーケンスが親とずれているか判定
			//------------------------------------------------------
			// ・メッセージシーケンスが遅れている
			// ・もしくは一人でもメッセージ表示中の奴がいる
			//------------------------------------------------------
			if( ( child_rec->MsgSeq < LocalMsgSeq ) || child_rec->bPrinting == TRUE )
			{
//				OS_TPrintf( "ParentMsgSeq:%d delay[%d] MsgSeq:%d \n", LocalMsgSeq, i, child_rec->MsgSeq );
				bDelay = TRUE;
			}

			//--------------------------------------------
			// 終了判定
			//--------------------------------------------
			if( child_rec->EndFlag == FALSE )
			{
				bEnd = FALSE;
			}
		}

		// 子機全員のEndFlagが立っていれば親機のEndFlagを立てる
		if( bEnd )
		{
			parent->EndFlag = TRUE;
		}

		//--------------------------------------------
		// メッセージウェイト判定保持
		//--------------------------------------------
		// ・一人でもずれていれば全員メッセージウェイトして良い
		// ・メッセージ表示以外のシーケンスが止まってしまうと困る
		//--------------------------------------------
		parent->bMsgWait = bDelay;

	} // end of parent proc

	// 子機 データ送信
	{
		OPED_COMM_CHILD_PTR child = PKTHLN_CommPack_GetData(&data->SendData);

		child->MsgSeq = LocalMsgSeq;
		child->bPrinting = MSG_CNT_IsPrinting( ptr->MsgCnt );
		child->EndFlag = ptr->EndFlag;
	} // end of child proc

	// 子機判定
	//・シェアデータのメッセージウェイトフラグが立っているとメッセージウェイト
	//・もし親の方がシーケンスが進んでいた場合、メッセージウェイトしない。
	return ( parent_rec->bMsgWait && LocalMsgSeq >= parent_rec->MsgSeq );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ENDING 通信処理
 *
 *	@param	PKTHLN_PTR work

 *	@retval TRUE:同期中（メッセージウェイトさせるべき）
 *
 *	@note	シーケンサが巻き戻ることも考慮している
 */
//-----------------------------------------------------------------------------
static BOOL ED_CommMain( PKTHLN_PTR work )
{
	int i;
	OPENING_PTR ptr = PTFrame_GetEventWorkPtr(work);
	COMM_EVENT_COMMON_DATA* data = PTFrame_GetEvtComCmnData(work);
	ENDING_COMM_PTR parent = PKTHLN_CommPack_GetData( &data->SendShareData );
	ENDING_COMM_PTR parent_rec = PKTHLN_CommPack_GetData( &data->ReciveShareData );

	u8 MyNetID = PTFrameGetCurrentID(work);
	u8 LocalMsgSeq = ptr->MsgSeq;

	BOOL bDelay = FALSE;

	// 親処理
	if( MyNetID == COMM_PARENT_ID )
	{
		BOOL bEnd = TRUE;

		// 送信メッセージシーケンス セット
		parent->MsgSeq = LocalMsgSeq;

		// 親の子機データは直接レシーバにセット
		{
			OPED_COMM_CHILD_PTR child;
			OPED_COMM_CHILD_PTR child_rec;

			child_rec = PKTHLN_CommPack_GetData(&data->ReciveData[0]);
			child = PKTHLN_CommPack_GetData(&data->SendData);
			(*child_rec) = (*child);
		}

		// レシーバー集計
		// (AIはメッセージを待たないので飛ばす)
		for( i=0; i<PTFrame_GetPlayerNum(work); i++ )
		{
			OPED_COMM_CHILD_PTR child_rec;

			child_rec = PKTHLN_CommPack_GetData(&data->ReciveData[i]);

			//------------------------------------------------------
			// 子のメッセージシーケンスが親とずれているか判定
			//------------------------------------------------------
			// ・メッセージシーケンスが遅れている
			// ・もしくは一人でもメッセージ表示中の奴がいる
			//------------------------------------------------------
			if( ( child_rec->MsgSeq < LocalMsgSeq ) || child_rec->bPrinting == TRUE )
			{
//				OS_TPrintf( "ParentMsgSeq:%d delay[%d] MsgSeq:%d \n", LocalMsgSeq, i, child_rec->MsgSeq );
				bDelay = TRUE;
			}

			//--------------------------------------------
			// 終了判定
			//--------------------------------------------
			if( child_rec->EndFlag == FALSE )
			{
				bEnd = FALSE;
			}
		}

		// 子機全員のEndFlagが立っていれば親機のEndFlagを立てる
		if( bEnd )
		{
			parent->EndFlag = TRUE;
		}

		//--------------------------------------------
		// メッセージウェイト判定保持
		//--------------------------------------------
		// ・一人でもずれていれば全員メッセージウェイトして良い
		// ・メッセージ表示以外のシーケンスが止まってしまうと困る
		//--------------------------------------------
		parent->bMsgWait = bDelay;

	} // end of parent proc

	// 子機 データ送信
	{
		OPED_COMM_CHILD_PTR child = PKTHLN_CommPack_GetData(&data->SendData);

		child->MsgSeq = LocalMsgSeq;
		child->bPrinting = MSG_CNT_IsPrinting( ptr->MsgCnt );
		child->EndFlag = ptr->EndFlag;
	} // end of child proc

	// 子機判定
	//・シェアデータのメッセージウェイトフラグが立っているとメッセージウェイト
	//・もし親の方がシーケンスが進んでいた場合、メッセージウェイトしない。
	return ( parent_rec->bMsgWait && LocalMsgSeq >= parent_rec->MsgSeq );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	OP:終了フラグを取得
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL OP_CheckEndFlag( PKTHLN_PTR work )
{
	GET_OP_RECIVE(work,data,parent);
	return ( parent->EndFlag );
}

//-----------------------------------------------------------------------------
/**
 *	@brief	ED:終了フラグを取得
 *
 *	@param	PKTHLN_PTR work
 *
 *	@retval
 */
//-----------------------------------------------------------------------------
static BOOL ED_CheckEndFlag( PKTHLN_PTR work )
{
	GET_ED_RECIVE(work,data,parent);
	return ( parent->EndFlag );
}